String.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / clr / src / BCL / System / String.cs / 1 / String.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
/*============================================================
** 
** Class:  String 
**
** 
** Purpose: Contains headers for the String class.  Actual implementations
** are in String.cpp
**
** 
===========================================================*/
namespace System { 
    using System.Text; 
    using System;
    using System.Runtime.ConstrainedExecution; 
    using System.Globalization;
    using System.Threading;
    using System.Collections;
    using System.Collections.Generic; 
    using System.Runtime.CompilerServices;
    using Microsoft.Win32; 
    using System.Runtime.InteropServices; 
    using va_list = System.ArgIterator;
    // 
    // For Information on these methods, please see COMString.cpp
    //
    // The String class represents a static string of characters.  Many of
    // the String methods perform some type of transformation on the current 
    // instance and return the result as a new String. All comparison methods are
    // implemented as a part of String.  As with arrays, character positions 
    // (indices) are zero-based. 
    //
    // When passing a null string into a constructor in VJ and VC, the null should be 
    // explicitly type cast to a String.
    // For Example:
    // String s = new String((String)null);
    // Text.Out.WriteLine(s); 
    //
[System.Runtime.InteropServices.ComVisible(true)] 
    [Serializable] public sealed class String : IComparable, ICloneable, IConvertible, IEnumerable 
#if GENERICS_WORK
        , IComparable, IEnumerable, IEquatable 
#endif
    {

        // 
        //NOTE NOTE NOTE NOTE
        //These fields map directly onto the fields in an EE StringObject.  See object.h for the layout. 
        // 
        [NonSerialized]private int  m_arrayLength;
        [NonSerialized]private int  m_stringLength; 
        [NonSerialized]private char m_firstChar;

        //private static readonly char FmtMsgMarkerChar='%';
        //private static readonly char FmtMsgFmtCodeChar='!'; 
        //These are defined in Com99/src/vm/COMStringCommon.h and must be kept in sync.
        private const int TrimHead = 0; 
        private const int TrimTail = 1; 
        private const int TrimBoth = 2;
 
        // The Empty constant holds the empty string value.
        //We need to call the String constructor so that the compiler doesn't mark this as a literal.
        //Marking this as a literal would mean that it doesn't show up as a field which we can access
        //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, String[] value) { 
            if (value==null) {
                throw new ArgumentNullException("value"); 
            } 
            return Join(separator, value, 0, value.Length);
        } 

#if WIN64
        private const int charPtrAlignConst = 3;
        private const int alignConst        = 7; 
#else
        private const int charPtrAlignConst = 1; 
        private const int alignConst        = 3; 
#endif
 
        internal char FirstChar { get { return m_firstChar; } }

        // Joins an array of strings together as one string with a separator between each original string.
        // 
        public unsafe static String Join(String separator, String[] value, int startIndex, int count) {
            //Treat null as empty string. 
            if (separator == null) { 
                separator = String.Empty;
            } 

            //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")); 
            } 

            //If count is 0, that skews a whole bunch of the calculations below, so just special case that. 
            if (count == 0) {
                return 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++) {
                if (value[stringToJoinIndex] != null) { 
                    jointLength += value[stringToJoinIndex].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] );
                }
                BCLDebug.Assert(*(pointerToJointString + charBuffer.Length) == '\0', "String must be null-terminated!");
            } 

            return jointString; 
        } 

 
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern int nativeCompareOrdinal(String strA, String strB, bool bIgnoreCase);

        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        internal static extern int nativeCompareOrdinalEx(String strA, int indexA, String strB, int indexB, int count);
        //This will not work in case-insensitive mode for any character greater than 0x80. 
        //We'll throw an ArgumentException. 
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        unsafe internal static extern int nativeCompareOrdinalWC(String strA, char *strBChars, bool bIgnoreCase, out bool success); 
        //
        // 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)
        // from the assembly.  This provides a workaround for that problem and should NOT be used anywhere else. 
        //
        internal unsafe static string SmallCharToUpper(string strIn) { 
            BCLDebug.Assert(strIn != null, "strIn"); 
            //
            // Get the length and pointers to each of the buffers.  Walk the length 
            // of the string and copy the characters from the inBuffer to the outBuffer,
            // capitalizing it if necessary.  We assert that all of our characters are
            // less than 0x80.
            // 
            int length = strIn.Length;
            String strOut = FastAllocateString(length); 
            fixed (char * inBuff = &strIn.m_firstChar, outBuff = &strOut.m_firstChar) { 
                char c;
 
                int upMask = ~0x20;
                for(int i = 0; i < length; i++) {
                    c = inBuff[i];
                    BCLDebug.Assert((int)c < 0x80, "(int)c < 0x80"); 

                    // 
                    // 0x20 is the difference between upper and lower characters in the lower 
                    // 128 ASCII characters. And this bit off to make the chars uppercase.
                    // 
                    if (c >= 'a' && c <= 'z') {
                        c = (char)((int)c & upMask);
                    }
                    outBuff[i] = c; 
                }
 
                BCLDebug.Assert(outBuff[length]=='\0', "outBuff[length]=='\0'"); 
            }
            return strOut; 
        }

        //
        // 
        // NATIVE INSTANCE METHODS
        // 
        // 

        // 
        // Search/Query methods
        //

        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] 
        private unsafe static bool EqualsHelper(String strA, String strB)
        { 
            int length = strA.Length; 
            if (length != strB.Length) return false;
 
            fixed(char* ap = strA) fixed(char* bp = strB)
            {
                char* a = ap;
                char* b = bp; 

                // unroll the loop 
#if AMD64 
                // 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 shorter
                // pathlength

                while (length >= 12) 
                {
                    if (*(long*)a     != *(long*)b) break; 
                    if (*(long*)(a+4) != *(long*)(b+4)) break; 
                    if (*(long*)(a+8) != *(long*)(b+8)) break;
                    a += 12; b += 12; length -= 12; 
                }
#else
                while (length >= 10)
                { 
                    if (*(int*)a != *(int*)b) break;
                    if (*(int*)(a+2) != *(int*)(b+2)) break; 
                    if (*(int*)(a+4) != *(int*)(b+4)) break; 
                    if (*(int*)(a+6) != *(int*)(b+6)) break;
                    if (*(int*)(a+8) != *(int*)(b+8)) break; 
                    a += 10; b += 10; length -= 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) break;
                    a += 2; b += 2; length -= 2;
                } 

                return (length <= 0); 
            } 
        }
 
        private unsafe static int CompareOrdinalHelper(String strA, String strB)
        {
            BCLDebug.Assert(strA != null && strB != null, "strings cannot be null!");
            int length = Math.Min(strA.Length, strB.Length); 
            int diffOffset = -1;
 
            fixed(char* ap = strA) fixed(char* bp = strB) 
            {
                char* a = ap; 
                char* b = bp;

                // unroll the loop
                while (length >= 10) 
                {
                    if (*(int*)a != *(int*)b) { 
                        diffOffset = 0; 
                        break;
                    } 

                    if (*(int*)(a+2) != *(int*)(b+2)) {
                        diffOffset = 2;
                        break; 
                    }
 
                    if (*(int*)(a+4) != *(int*)(b+4)) { 
                        diffOffset = 4;
                        break; 
                    }

                    if (*(int*)(a+6) != *(int*)(b+6)) {
                        diffOffset = 6; 
                        break;
                    } 
 
                    if (*(int*)(a+8) != *(int*)(b+8)) {
                        diffOffset = 8; 
                        break;
                    }
                    a += 10;
                    b += 10; 
                    length -= 10;
                } 
 
                if( diffOffset != -1) {
                    // we already see a difference in the unrolled loop above 
                    a += diffOffset;
                    b += diffOffset;
                    int order;
                    if ( (order = (int)*a - (int)*b) != 0) { 
                        return order;
                    } 
                    BCLDebug.Assert( *(a+1) != *(b+1), "This byte must be different if we reach here!"); 
                    return ((int)*(a+1) - (int)*(b+1));
                } 

                // now go back to slower code path and do comparison on 4 bytes one time.
                // Following code also take advantage of the fact strings will
                // use even numbers of characters (runtime will have a extra zero at the end.) 
                // so even if length is 1 here, we can still do the comparsion.
                while (length > 0) { 
                    if (*(int*)a != *(int*)b) { 
                        break;
                    } 
                    a += 2;
                    b += 2;
                    length -= 2;
                } 

                if( length > 0) { 
                    int c; 
                    // found a different int on above loop
                    if ( (c = (int)*a - (int)*b) != 0) { 
                        return c;
                    }
                    BCLDebug.Assert( *(a+1) != *(b+1), "This byte must be different if we reach here!");
                    return ((int)*(a+1) - (int)*(b+1)); 
                }
 
                // 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; 
            }
        }

        // Determines whether two strings match. 
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        public override bool Equals(Object obj) { 
            String str = obj as String; 
            if (str == null)
            { 
                // exception will be thrown later for null this
                if (this != null) return false;
            }
 
            return EqualsHelper(this, str);
        } 
 
        // Determines whether two strings match.
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] 
        public bool Equals(String value) {
            if (value == null)
            {
                // exception will be thrown later for null this 
                if (this != null) return false;
            } 
 
            return EqualsHelper(this, value);
        } 

        public bool Equals(String value, StringComparison comparisonType) {
            if( comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase) {
                throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType"); 
            }
 
            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:
                    return this.Equals(value);

                case StringComparison.OrdinalIgnoreCase: 
                    if( this.Length != value.Length)
                        return false; 
                    else { 
                        // If both strings are ASCII strings, we can take the fast path.
                        if (this.IsAscii() && value.IsAscii()) { 
                            return (String.nativeCompareOrdinal(this, value, true) == 0);
                        }
                        // Take the slow path.
                        return (TextInfo.CompareOrdinalIgnoreCase(this, value) == 0); 
                    }
 
                default: 
                    throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
            } 
        }


        // Determines whether two Strings match. 
        public static bool Equals(String a, String b) {
            if ((Object)a==(Object)b) { 
                return true; 
            }
 
            if ((Object)a==null || (Object)b==null) {
                return false;
            }
 
            return EqualsHelper(a, b);
        } 
 
        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");
            }

            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: 
                    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 (String.nativeCompareOrdinal(a, b, true) == 0); 
                        }
                        // Take the slow path. 

                        return (TextInfo.CompareOrdinalIgnoreCase(a, b) == 0);
                    }
                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.
        // 
        [System.Runtime.CompilerServices.IndexerName("Chars")]
        public extern char this[int index] {
            [MethodImpl(MethodImplOptions.InternalCall)]
            get; 
        }
 
        // Converts a substring of this string to an array of characters.  Copies the 
        // characters of this string beginning at position startIndex and ending at
        // startIndex + length - 1 to the character array buffer, beginning 
        // at bufferStartIndex.
        //
        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"));
 
            // 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. 
        unsafe public char[] ToCharArray() {
            //  huge performance improvement for short strings by doing this  
            int length = Length;
            char[] chars = new char[length];
            if (length > 0)
            { 
                fixed (char* src = &this.m_firstChar)
                    fixed (char* dest = chars) 
                        wstrcpyPtrAligned(dest, src, length); 
            }
            return chars; 
        }

        // Returns a substring of this string as an array of characters.
        // 
        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"));

            char[] chars = new char[length]; 
            if(length > 0)
            { 
                fixed (char* src = &this.m_firstChar) 
                    fixed (char* dest = chars) {
                        wstrcpy(dest, src + startIndex, length); 
                    }
            }
            return chars;
        } 

        public static bool IsNullOrEmpty(String value) { 
            return (value == null || value.Length == 0); 
        }
 
        // 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.
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        public override int GetHashCode() { 
            unsafe {
                fixed (char *src = this) { 
                    BCLDebug.Assert(src[this.Length] == '\0', "src[this.Length] == '\\0'"); 
                    BCLDebug.Assert( ((int)src)%4 == 0, "Managed string should start at 4 bytes boundary");
 
#if WIN32
                    int hash1 = (5381<<16) + 5381;
#else
                    int hash1 = 5381; 
#endif
                    int hash2 = hash1; 
 
#if WIN32
                    // 32bit machines. 
                    int* pint = (int *)src;
                    int len = this.Length;
                    while(len > 0) {
                        hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0]; 
                        if( len <= 2) {
                            break; 
                        } 
                        hash2 = ((hash2 << 5) + hash2 + (hash2 >> 27)) ^ pint[1];
                        pint += 2; 
                        len  -= 4;
                    }
#else
                    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;
                    } 
#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.
        // 
        public extern int Length { 
            [MethodImplAttribute(MethodImplOptions.InternalCall)]
            get; 
        }

        ///
        internal int ArrayLength { 
            get { return (m_arrayLength); }
        } 
 
        // Used by StringBuilder
        internal int Capacity { 
            get { return (m_arrayLength - 1); }
        }

        // Creates an array of strings by splitting this string at each 
        // occurence of a separator.  The separator is searched for, and if found,
        // the substring preceding the occurence is stored as the first element in 
        // the array of strings.  We then continue in this manner by searching 
        // the substring that follows the occurence.  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) { 
            return Split(separator, Int32.MaxValue, StringSplitOptions.None);
        } 
 
        // Creates an array of strings by splitting this string at each
        // occurence of a separator.  The separator is searched for, and if found, 
        // the substring preceding the occurence is stored as the first element in
        // the array of strings.  We then continue in this manner by searching
        // the substring that follows the occurence.  On the other hand, if the separator
        // is not found, the array of strings will contain this instance as its only element. 
        // If the spearator 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) {
            return Split(separator, count, StringSplitOptions.None);
        }
 
        [ComVisible(false)]
        public String[] Split(char[] separator, StringSplitOptions options) { 
            return Split(separator, Int32.MaxValue, options); 
        }
 
        [ComVisible(false)]
        public String[] Split(char[] separator, 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", (int)options)); 
            }

            bool omitEmptyEntries = (options == StringSplitOptions.RemoveEmptyEntries);
            if( (count == 0) || (omitEmptyEntries && this.Length ==0)) { 
                return new String[0];
            } 
 
            int[] sepList = new int[Length];
            int numReplaces = MakeSeparatorList(separator, ref sepList); 

            //Handle the special case of no replaces and special count.
            if (0 == numReplaces || count == 1) {
                String[] stringArray = new String[1]; 
                stringArray[0] = this;
                return stringArray; 
            } 

            if(omitEmptyEntries) { 
                return InternalSplitOmitEmptyEntries(sepList, null, numReplaces, count);
            }
            else {
                return InternalSplitKeepEmptyEntries(sepList, null, numReplaces, count); 
            }
        } 
 
        [ComVisible(false)]
        public String [] Split(String[] separator, StringSplitOptions options) { 
            return Split(separator, Int32.MaxValue, options);
        }

        [ComVisible(false)] 
        public String[] Split(String[] separator, 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));
            } 

            bool omitEmptyEntries = (options == StringSplitOptions.RemoveEmptyEntries); 
 
            if (separator == null || separator.Length ==0) {
                return Split((char[]) null, count, options); 
            }

            if( (count == 0) || (omitEmptyEntries && this.Length ==0)) {
                return new String[0]; 
            }
 
            int[] sepList = new int[Length]; 
            int[] lengthList = new int[Length];
            int numReplaces = MakeSeparatorList(separator, ref sepList, ref lengthList); 

            //Handle the special case of no replaces and special count.
            if (0 == numReplaces || count == 1) {
                String[] stringArray = new String[1]; 
                stringArray[0] = this;
                return stringArray; 
            } 

            if(omitEmptyEntries) { 
                return InternalSplitOmitEmptyEntries(sepList, lengthList, numReplaces, count);
            }
            else {
                return InternalSplitKeepEmptyEntries(sepList, lengthList, numReplaces, count); 
            }
        } 
 
        // Note a few 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 numReplaces, int count) { 
            BCLDebug.Assert( count >= 2, "Count>=2");
 
            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) ? 1 : 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 numReplaces, int count) {
            BCLDebug.Assert( count >= 2, "Count>=2");
 
            // 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) ? 1 : 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) ? 1 : lengthList[i]);
                    } 
                    break; 
                }
            } 

            // we must have at least one slot left to fill in the last string.
            BCLDebug.Assert( arrIndex < maxItems, "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 number of the places within baseString where
        // instances of characters in Separator occur. 
        // Args: separator  -- A string containing all of the split characters.
        //       sepList    -- an array of ints for split char indicies. 
        //------------------------------------------------------------------- 
        private unsafe int MakeSeparatorList(char[] separator, ref int[] sepList) {
            int foundCount=0; 

            if (separator == null || separator.Length ==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; 
                int sepCount = separator.Length;
                //If they passed in a string of chars, actually look for those chars. 
                fixed (char* pwzChars = &this.m_firstChar, pSepChars = separator) { 
                    for (int i=0; i< Length && foundCount < sepListCount; i++) {
                        char * pSep = pSepChars; 
                        for( int j =0; j < sepCount; j++, pSep++) {
                           if ( pwzChars[i] == *pSep) {
                               sepList[foundCount++]=i;
                               break; 
                           }
                        } 
                    } 
                }
            } 
            return foundCount;
        }

        //------------------------------------------------------------------- 
        // This function returns number of the places within baseString 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. 
        //--------------------------------------------------------------------
        private unsafe int MakeSeparatorList(String[] separators, ref int[] sepList, ref int[] lengthList) {
            BCLDebug.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.
        // 
        public String Substring (int startIndex, int length) {
 	    // okay to not enforce copying in the case of Substring(0, length), since we assume 
	    // String instances are immutable. 
	    return InternalSubStringWithChecks(startIndex, length, false);
	}	 
 	

        internal String InternalSubStringWithChecks (int startIndex, int length, bool fAlwaysCopy) {
 
            int thisLength = Length;
 
            //Bounds Checking. 
            if (startIndex<0) {
                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex")); 
            }

            if (startIndex > thisLength) {
                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndexLargerThanLength")); 
            }
 
            if (length<0) { 
                throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
            } 

            if (startIndex > thisLength-length) {
                throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_IndexLength"));
            } 

            if( length == 0) { 
                return String.Empty; 
            }
            return InternalSubString(startIndex, length, fAlwaysCopy); 
        }

        unsafe string InternalSubString(int startIndex, int length, bool fAlwaysCopy) {
            BCLDebug.Assert( startIndex >= 0 && startIndex <= this.Length, "StartIndex is out of range!"); 
            BCLDebug.Assert( length >= 0 && startIndex <= this.Length - length, "length is out of range!");
 
            if( startIndex == 0 && length == this.Length && !fAlwaysCopy)  { 
                return this;
            } 

            String result = FastAllocateString(length);

            fixed(char* dest = &result.m_firstChar) 
                fixed(char* src = &this.m_firstChar) {
                    wstrcpy(dest, src + startIndex, length); 
                } 

            return result; 
        }

        //This should really live on System.Globalization.CharacterInfo.  However,
        //Trim gets called by security while resgen is running, so we can't run 
        //CharacterInfo's class initializer (which goes to native and looks for a
        //resource table that hasn't yet been attached to the assembly when resgen 
        //runs. 
        internal static readonly char[] WhitespaceChars =
            { (char) 0x9, (char) 0xA, (char) 0xB, (char) 0xC, (char) 0xD, (char) 0x20,   (char) 0x85, 
              (char) 0xA0, (char)0x1680,
              (char) 0x2000, (char) 0x2001, (char) 0x2002, (char) 0x2003, (char) 0x2004, (char) 0x2005,
              (char) 0x2006, (char) 0x2007, (char) 0x2008, (char) 0x2009, (char) 0x200A, (char) 0x200B,
              (char) 0x2028, (char) 0x2029, 
              (char) 0x3000, (char) 0xFEFF };
 
        // Removes a string of characters from the ends of this string. 
        public String Trim(params char[] trimChars) {
            if (null==trimChars || trimChars.Length == 0) { 
                trimChars=WhitespaceChars;
            }
            return TrimHelper(trimChars,TrimBoth);
        } 

        // Removes a string of characters from the beginning of this string. 
        public String TrimStart(params char[] trimChars) { 
            if (null==trimChars || trimChars.Length == 0) {
                trimChars=WhitespaceChars; 
            }
            return TrimHelper(trimChars,TrimHead);
        }
 

        // Removes a string of characters from the end of this string. 
        public String TrimEnd(params char[] trimChars) { 
            if (null==trimChars || trimChars.Length == 0) {
                trimChars=WhitespaceChars; 
            }
            return TrimHelper(trimChars,TrimTail);
        }
 

        // Creates a new string with the characters copied in from ptr. If 
        // ptr is null, a string initialized to ";<;No Object>;"; (i.e., 
        // String.NullString) is created.
        // 
        [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
        unsafe public extern String(char *value);
        [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
        unsafe public extern String(char *value, int startIndex, int length); 

        [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)] 
       unsafe public extern String(sbyte *value); 
        [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
        unsafe public extern String(sbyte *value, int startIndex, int length); 

        [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
        unsafe public extern String(sbyte *value, int startIndex, int length, Encoding enc);
 
        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((byte*)value, startIndex, b, 0, 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 
        unsafe static internal String CreateStringFromEncoding( 
            byte* bytes, int byteLength, Encoding encoding)
        { 
            BCLDebug.Assert(bytes != null, "need a byte[].");
            BCLDebug.Assert(byteLength >= 0, "byteLength >= 0");

            // Get our string length 
            int stringLength = encoding.GetCharCount(bytes, byteLength, null);
            BCLDebug.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); 
                BCLDebug.Assert(stringLength == doubleCheck,
                    "Expected encoding.GetChars to return same length as encoding.GetCharCount"); 
            }

            return s;
        } 

        unsafe internal byte[] ConvertToAnsi_BestFit_Throw(int iMaxDBCSCharByteSize) 
        { 
            const uint CP_ACP = 0;
            int nb; 

            int cbNativeBuffer = (Length + 3) * iMaxDBCSCharByteSize;
            byte[] bytes = new byte[ cbNativeBuffer ];
 
            uint flgs = 0;
            uint DefaultCharUsed = 0; 
 
            fixed (byte* pbNativeBuffer = bytes)
            { 
                fixed (char* pwzChar = &this.m_firstChar)
                {
                    nb = Win32Native.WideCharToMultiByte(
                        CP_ACP, 
                        flgs,
                        pwzChar, 
                        this.Length, 
                        pbNativeBuffer,
                        cbNativeBuffer, 
                        IntPtr.Zero,
                        new IntPtr(&DefaultCharUsed));
                }
            } 

            if (0 != DefaultCharUsed) 
            { 
                throw new ArgumentException(Environment.GetResourceString("Interop_Marshal_Unmappable_Char"));
            } 

            bytes[nb] = 0;
            return bytes;
        } 

        // Normalization Methods 
        // These just wrap calls to Normalization class 
        public bool IsNormalized()
        { 
            // Default to Form C
            return IsNormalized(NormalizationForm.FormC);
        }
 
        public bool IsNormalized(NormalizationForm normalizationForm)
        { 
            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;
            } 
            return Normalization.IsNormalized(this, normalizationForm); 
        }
 
        public String Normalize()
        {
            // Default to Form C
            return Normalize(NormalizationForm.FormC); 
        }
 
        public String Normalize(NormalizationForm normalizationForm) 
        {
            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; 
            }
            return Normalization.Normalize(this, normalizationForm); 
        }

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        private extern static String FastAllocateString(int length); 

        unsafe private static void FillStringChecked(String dest, int destPos, String src) 
        { 
            int length = src.Length;
 
            if (length > dest.Length - destPos) {
                throw new IndexOutOfRangeException();
            }
 
            fixed(char *pDest = &dest.m_firstChar)
                fixed (char *pSrc = &src.m_firstChar) { 
                    wstrcpy(pDest + destPos, pSrc, 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. 
        //
        [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.
        //

        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        public extern String(char [] value);
 
        // 
        // This handles the case where both smem and dmem pointers are
        //  aligned on a pointer boundary 
        //
        private static unsafe void wstrcpyPtrAligned(char *dmem, char *smem, int charCount)
        {
#if _DEBUG 
            BCLDebug.Assert(((int)dmem & (IntPtr.Size-1)) == 0, "dmem is pointer size aligned");
            BCLDebug.Assert(((int)smem & (IntPtr.Size-1)) == 0, "smem is pointer size aligned"); 
#endif 

#if !WIN64 
            while (charCount >= 8)
            {
                ((uint *)dmem)[0] = ((uint *)smem)[0];
                ((uint *)dmem)[1] = ((uint *)smem)[1]; 
                ((uint *)dmem)[2] = ((uint *)smem)[2];
                ((uint *)dmem)[3] = ((uint *)smem)[3]; 
 
                dmem      += 8;
                smem      += 8; 
                charCount -= 8;
            }
            if ((charCount & 4) != 0)
            { 
                ((uint *)dmem)[0] = ((uint *)smem)[0];
                ((uint *)dmem)[1] = ((uint *)smem)[1]; 
                dmem += 4; 
                smem += 4;
            } 
#else
            while (charCount >= 16)
            {
                ((ulong *)dmem)[0] = ((ulong *)smem)[0]; 
                ((ulong *)dmem)[1] = ((ulong *)smem)[1];
                ((ulong *)dmem)[2] = ((ulong *)smem)[2]; 
                ((ulong *)dmem)[3] = ((ulong *)smem)[3]; 

                dmem      += 16; 
                smem      += 16;
                charCount -= 16;
            }
 
            if ((charCount & 8) != 0)
            { 
                ((ulong *)dmem)[0] = ((ulong *)smem)[0]; 
                ((ulong *)dmem)[1] = ((ulong *)smem)[1];
                dmem += 8; 
                smem += 8;
            }
            if ((charCount & 4) != 0)
            { 
                ((ulong *)dmem)[0] = ((ulong *)smem)[0];
                dmem += 4; 
                smem += 4; 
            }
#endif 
            if ((charCount & 2) != 0)
            {
                ((uint *)dmem)[0] = ((uint *)smem)[0];
                dmem += 2; 
                smem += 2;
            } 
 
            if ((charCount & 1) != 0)
            { 
                dmem[0] = smem[0];
            }
        }
 
        private static unsafe void wstrcpy(char *dmem, char *smem, int charCount)
        { 
            if (charCount > 0) { 
#if ALIGN_ACCESS
                if ((((int)dmem | (int)smem) & 1) == 0) { 
#endif
                    // First Align dmem to a pointer boundary
                    if (((int)dmem & 2) != 0)
                    { 
                        dmem[0] = smem[0];
                        dmem      += 1; 
                        smem      += 1; 
                        charCount -= 1;
                    } 
#if WIN64
                    if ((((int)dmem & 4) != 0) && (charCount >= 2))
                    {
#if IA64 
                        if (((int)smem & 2) != 0)
                        { 
                            dmem[0] = smem[0]; 
                            dmem[1] = smem[1];
                        } 
                        else
#endif
                        {
                            ((uint *)dmem)[0] = ((uint *)smem)[0]; 
                        }
                        dmem += 2; 
                        smem += 2; 
                        charCount -= 2;
                    } 
#endif
                    // Both x86 and AMD64 perform much faster if all writes are pointer aligned
                    // Unaligned reads perform better than 2-byte aligned reads and
                    //  better than pointer aligned reads with 16-bit shift and OR operation 
                    // So on x86 or AMD64 after aligning dmem to a pointer boundry
                    //  we just use standard mechanism 
#if !WIN64 
                    while (charCount >= 8)
                    { 
                        ((uint *)dmem)[0] = ((uint *)smem)[0];
                        ((uint *)dmem)[1] = ((uint *)smem)[1];
                        ((uint *)dmem)[2] = ((uint *)smem)[2];
                        ((uint *)dmem)[3] = ((uint *)smem)[3]; 
                        dmem      += 8;
                        smem      += 8; 
                        charCount -= 8; 
                    }
                    if ((charCount & 4) != 0) 
                    {
                        ((uint *)dmem)[0] = ((uint *)smem)[0];
                        ((uint *)dmem)[1] = ((uint *)smem)[1];
                        dmem += 4; 
                        smem += 4;
                    } 
                    if ((charCount & 2) != 0) 
                    {
                        ((uint *)dmem)[0] = ((uint *)smem)[0]; 
                        dmem += 2;
                        smem += 2;
                    }
#else 
#if AMD64
                    while (charCount >= 16) 
                    { 
                        ((ulong *)dmem)[0] = ((ulong *)smem)[0];
                        ((ulong *)dmem)[1] = ((ulong *)smem)[1]; 
                        ((ulong *)dmem)[2] = ((ulong *)smem)[2];
                        ((ulong *)dmem)[3] = ((ulong *)smem)[3];
                        dmem      += 16;
                        smem      += 16; 
                        charCount -= 16;
                    } 
                    if ((charCount & 8) != 0) 
                    {
                        ((ulong *)dmem)[0] = ((ulong *)smem)[0]; 
                        ((ulong *)dmem)[1] = ((ulong *)smem)[1];
                        dmem += 8;
                        smem += 8;
                    } 
                    if ((charCount & 4) != 0)
                    { 
                        ((ulong *)dmem)[0] = ((ulong *)smem)[0]; 
                        dmem += 4;
                        smem += 4; 
                    }
                    if ((charCount & 2) != 0)
                    {
                        ((uint *)dmem)[0] = ((uint *)smem)[0]; 
                        dmem += 2;
                        smem += 2; 
                    } 
#elif IA64
                    // On IA64 we MUST use aligned reads otherwise 
                    // we will fault
                    if (((int)smem & 2) == 0)
                    {
                        // align is 0 or 4 
                        if  (((int)smem & alignConst) == 0)
                        { 
                            while (charCount >= 16) 
                            {
                                ((ulong *)dmem)[0] = ((ulong *)smem)[0]; 
                                ((ulong *)dmem)[1] = ((ulong *)smem)[1];
                                ((ulong *)dmem)[2] = ((ulong *)smem)[2];
                                ((ulong *)dmem)[3] = ((ulong *)smem)[3];
                                dmem      += 16; 
                                smem      += 16;
                                charCount -= 16; 
                            } 

                            if ((charCount & 8) != 0) 
                            {
                                ((ulong *)dmem)[0] = ((ulong *)smem)[0];
                                ((ulong *)dmem)[1] = ((ulong *)smem)[1];
                                dmem += 8; 
                                smem += 8;
                            } 
 
                            if ((charCount & 4) != 0)
                            { 
                                ((ulong *)dmem)[0] = ((ulong *)smem)[0];
                                dmem += 4;
                                smem += 4;
                            } 
                        }
                        else // align is 4 
                        { 
                            while (charCount >= 8)
                            { 
                                ((uint *)dmem)[0] = ((uint *)smem)[0];
                                ((uint *)dmem)[1] = ((uint *)smem)[1];
                                ((uint *)dmem)[2] = ((uint *)smem)[2];
                                ((uint *)dmem)[3] = ((uint *)smem)[3]; 
                                dmem      += 8;
                                smem      += 8; 
                                charCount -= 8; 
                            }
 
                            if ((charCount & 4) != 0)
                            {
                                ((uint *)dmem)[0] = ((uint *)smem)[0];
                                ((uint *)dmem)[1] = ((uint *)smem)[1]; 
                                dmem += 4;
                                smem += 4; 
                            } 
                        }
                        if ((charCount & 2) != 0) 
                        {
                            ((uint *)dmem)[0] = ((uint *)smem)[0];
                            dmem += 2;
                            smem += 2; 
                        }
                    } 
                    else // align is 2 or 6 
                    {
                        while (charCount >= 8) 
                        {
                            dmem[0] = smem[0];
                            dmem[1] = smem[1];
                            dmem[2] = smem[2]; 
                            dmem[3] = smem[3];
                            dmem[4] = smem[4]; 
                            dmem[5] = smem[5]; 
                            dmem[6] = smem[6];
                            dmem[7] = smem[7]; 
                            dmem += 8;
                            smem += 8;
                            charCount -= 8;
                        } 

                        if ((charCount & 4) != 0) 
                        { 
                            dmem[0] = smem[0];
                            dmem[1] = smem[1]; 
                            dmem[2] = smem[2];
                            dmem[3] = smem[3];
                            dmem += 4;
                            smem += 4; 
                        }
                        if ((charCount & 2) != 0) 
                        { 
                            dmem[0] = smem[0];
                            dmem[1] = smem[1]; 
                            dmem += 2;
                            smem += 2;
                        }
                    } 
#endif
#endif 
                    if ((charCount & 1) != 0) 
                    {
                        dmem[0] = smem[0]; 
                    }
#if ALIGN_ACCESS
                }
                else 
                {
                    // This is rare case where at least one of the pointers is only byte aligned. 
                    do { 
                        ((byte *)dmem)[0] = ((byte *)smem)[0];
                        ((byte *)dmem)[1] = ((byte *)smem)[1]; 
                        charCount -= 1;
                        dmem += 1;
                        smem += 1;
                    } 
                    while (charCount > 0);
                } 
#endif 
            }
        } 

        private String CtorCharArray(char [] value)
        {
            if (value != null && value.Length != 0) { 
                String result = FastAllocateString(value.Length);
 
                unsafe { 
                    fixed (char * dest = result, source = value) {
                        wstrcpyPtrAligned(dest, source, value.Length); 
                    }
                }
                return result;
            } 
            else
                return String.Empty; 
        } 

        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"));
 
            if (length > 0) {
                String result = FastAllocateString(length); 
 
                unsafe {
                    fixed (char * dest = result, source = value) { 
                        wstrcpy(dest, source + startIndex, length);
                    }
                }
                return result; 
            }
            else 
                return String.Empty; 
        }
 
        private String CtorCharCount(char c, int count)
        {
            if (count > 0) {
                String result = FastAllocateString(count); 
                unsafe {
                    fixed (char *dest = result) { 
                        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"));
        } 

        private static unsafe int wcslen(char *ptr)
        {
            char *end = ptr; 

            // The following code is (somewhat surprisingly!) significantly faster than a naive loop, 
            // at least on x86 and the current jit. 

            // First make sure our pointer is aligned on a dword boundary 
            while (((uint)end & 3) != 0 && *end != 0)
                end++;
            if (*end != 0) {
                // 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 page, so they're either both accessible, or both not.

                while ((end[0] & end[1]) != 0 || (end[0] != 0 && end[1] != 0)) {
                    end += 2; 
                }
            } 
            // finish up with the naive loop 
            for ( ; *end != 0; end++)
                ; 

            int count = (int)(end - ptr);

            return count; 
        }
 
        private unsafe String CtorCharPtr(char *ptr) 
        {
            BCLDebug.Assert(this == null, "this == null");        // this is the string constructor, we allocate it 
            if (ptr >= (char *)64000) {
                try {
                    int count = wcslen(ptr);
                    String result = FastAllocateString(count); 
                    fixed (char *dest = result)
                        wstrcpy(dest, ptr, count); 
                    return result; 
                }
                catch (NullReferenceException) { 
                    throw new ArgumentOutOfRangeException("ptr", Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));
                }
            }
            else if (ptr == null) 
                return String.Empty;
            else 
                throw new ArgumentException(Environment.GetResourceString("Arg_MustBeStringPtrNotAtom")); 
        }
 
        private unsafe String CtorCharPtrStartLength(char *ptr, int startIndex, int length)
        {
            BCLDebug.Assert(this == null, "this == null");        // this is the string constructor, we allocate it
            if (length < 0) { 
                throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
            } 
 
            if (startIndex < 0) {
                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex")); 
            }

            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")); 
            } 

            String result = FastAllocateString(length); 

            try {
                fixed(char *dest = result)
                    wstrcpy(dest, pFrom, length); 
                return result;
            } 
            catch (NullReferenceException) { 
                throw new ArgumentOutOfRangeException("ptr", Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));
            } 
        }

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public extern String(char c, int count); 

        // 
        // 
        // INSTANCE METHODS
        // 
        //

        // 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.
        // 
        public static int Compare(String strA, String strB) { 
            return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.None);
        } 

        // 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
        // 
        public static int Compare(String strA, String strB, bool ignoreCase) { 
            if (ignoreCase) {
                return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase); 
            }
            return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.None);
        }
 
        // Provides a more flexible function for string comparision. See StringComparison
        // for meaning of different comparisonType. 
        public static int Compare(String strA, String strB, StringComparison comparisonType) { 
            if( comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase) {
                throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType"); 
            }

            if ((Object)strA == (Object)strB) {
                return 0; 
            }
 
            //they can't both be null; 
            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:
                    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 (String.nativeCompareOrdinal(strA, strB, true)); 
                    }
                    // Take the slow path.
                    return TextInfo.CompareOrdinalIgnoreCase(strA, strB);
 
                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.
        // The case-sensitive option is set by ignoreCase, and the culture is set 
        // by culture
        // 
        public static int Compare(String strA, String strB, bool ignoreCase, CultureInfo culture) { 
            if (culture==null) {
                throw new ArgumentNullException("culture"); 
            }

            if (ignoreCase) {
                return culture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase); 
            }
            return culture.CompareInfo.Compare(strA, strB, CompareOptions.None); 
        } 

        // 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.
        //
        public static int Compare(String strA, int indexA, String strB, int indexB, int length) { 
            int lengthA = length;
            int lengthB = length; 
 
            if (strA!=null) {
                if (strA.Length - indexA < lengthA) { 
                  lengthA = (strA.Length - indexA);
                }
            }
 
            if (strB!=null) {
                if (strB.Length - indexB < lengthB) { 
                    lengthB = (strB.Length - indexB); 
                }
            } 
            return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None);
        }

 
        // 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. 
        //
        public static int Compare(String strA, int indexA, String strB, int indexB, int length, bool ignoreCase) { 
            int lengthA = length;
            int lengthB = length;

            if (strA!=null) { 
                if (strA.Length - indexA < lengthA) {
                  lengthA = (strA.Length - indexA); 
                } 
            }
 
            if (strB!=null) {
                if (strB.Length - indexB < lengthB) {
                    lengthB = (strB.Length - indexB);
                } 
            }
 
            if (ignoreCase) { 
                return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.IgnoreCase);
            } 
            return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None);
        }

        // 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. 
        //
        public static int Compare(String strA, int indexA, String strB, int indexB, int length, bool ignoreCase, CultureInfo culture) { 
            if (culture==null) {
                throw new ArgumentNullException("culture");
            }
 
            int lengthA = length;
            int lengthB = length; 
 
            if (strA!=null) {
                if (strA.Length - indexA < lengthA) { 
                  lengthA = (strA.Length - indexA);
                }
            }
 
            if (strB!=null) {
                if (strB.Length - indexB < lengthB) { 
                    lengthB = (strB.Length - indexB); 
                }
            } 

            if (ignoreCase) {
                return culture.CompareInfo.Compare(strA,indexA,lengthA, strB, indexB, lengthB,CompareOptions.IgnoreCase);
            } else { 
                return culture.CompareInfo.Compare(strA,indexA,lengthA, strB, indexB, lengthB,CompareOptions.None);
            } 
        } 

        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");
            }
 
            if (strA == null || strB == null) {
                 if ((Object)strA==(Object)strB) { //they're both null; 
                     return 0; 
                 }
 
                 return (strA==null)? -1 : 1; //-1 if A is null, 1 if B is null.
            }

            if (length < 0) { 
                throw new ArgumentOutOfRangeException("length",
                                                      Environment.GetResourceString("ArgumentOutOfRange_NegativeLength")); 
            } 

            if (indexA < 0) { 
                throw new ArgumentOutOfRangeException("indexA",
                                                     Environment.GetResourceString("ArgumentOutOfRange_Index"));
            }
 
            if (indexB < 0) {
                throw new ArgumentOutOfRangeException("indexB", 
                                                     Environment.GetResourceString("ArgumentOutOfRange_Index")); 
            }
 
            if(strA.Length - indexA <0 )  {
                throw new ArgumentOutOfRangeException("indexA",
                                                      Environment.GetResourceString("ArgumentOutOfRange_Index"));
            } 

            if(strB.Length - indexB <0 )  { 
                throw new ArgumentOutOfRangeException("indexB", 
                                                      Environment.GetResourceString("ArgumentOutOfRange_Index"));
            } 

            if( ( length == 0 )  ||
                ((strA == strB) && (indexA == indexB)) ){
                return 0; 
            }
 
            int lengthA = length; 
            int lengthB = length;
 
            if (strA!=null) {
                if (strA.Length - indexA < lengthA) {
                  lengthA = (strA.Length - indexA);
                } 
            }
 
            if (strB!=null) { 
                if (strB.Length - indexB < lengthB) {
                    lengthB = (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 nativeCompareOrdinalEx(strA, indexA, strB, indexB, length); 

                case StringComparison.OrdinalIgnoreCase:
                    return (TextInfo.CompareOrdinalIgnoreCaseEx(strA, indexA, strB, indexB, length));
 
                default:
                    throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison")); 
            } 

        } 

        // Compares this object to another 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.  Strings are considered to be
        // greater than all non-String objects.  Note that this means sorted 
        // arrays would contain nulls, other objects, then Strings in that order. 
        //
        public int CompareTo(Object value) { 
            if (value == null) {
                return 1;
            }
 
            if (!(value is String)) {
                throw new ArgumentException(Environment.GetResourceString("Arg_MustBeString")); 
            } 

            return String.Compare(this,(String)value, StringComparison.CurrentCulture); 
        }

        // Determines the sorting relation of StrB to the current instance.
        // 
        public int CompareTo(String strB) {
            if (strB==null) { 
                return 1; 
            }
            return CultureInfo.CurrentCulture.CompareInfo.Compare(this, strB, 0); 
        }

        // Compares strA and strB using an ordinal (code-point) comparison.
        // 
        public static int CompareOrdinal(String strA, String strB) {
            if ((Object)strA == (Object)strB) { 
                return 0; 
            }
 
            //they can't both be null;
            if( strA == null) {
                return -1;
            } 

            if( strB == null) { 
                return 1; 
            }
 
            return CompareOrdinalHelper(strA, strB);
        }

 
        // Compares strA and strB using an ordinal (code-point) comparison.
        // 
        public static int CompareOrdinal(String strA, int indexA, String strB, int indexB, int length) { 
           if (strA == null || strB == null) {
                if ((Object)strA==(Object)strB) { //they're both null; 
                    return 0;
                }

                return (strA==null)? -1 : 1; //-1 if A is null, 1 if B is null. 
            }
 
            return nativeCompareOrdinalEx(strA, indexA, strB, indexB, length); 
        }
 
        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. 
        //
        public Boolean EndsWith(String value) {
            return EndsWith(value, false, null);
        } 

        [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"); 
            }
 
            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 : (nativeCompareOrdinalEx(this, this.Length -value.Length, value, 0, value.Length) == 0);

                case StringComparison.OrdinalIgnoreCase: 
                    return this.Length < value.Length ? false : (TextInfo.CompareOrdinalIgnoreCaseEx(this, this.Length -value.Length, value, 0, value.Length) == 0);
 
                default: 
                    throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
            } 
        }

        public Boolean EndsWith(String value, Boolean ignoreCase, CultureInfo culture) {
            if (null==value) { 
                throw new ArgumentNullException("value");
            } 
 
            if((object)this == (object)value) {
                return true; 
            }

            CultureInfo referenceCulture = (culture == null) ? CultureInfo.CurrentCulture : culture;
            return referenceCulture.CompareInfo.IsSuffix(this, value, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None); 
        }
 
        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 occurance of value in the current instance.
        // The search starts at startIndex and runs thorough the next count characters. 
        //
        public int IndexOf(char value) {
            return IndexOf(value, 0, this.Length);
        } 

        public int IndexOf(char value, int startIndex) { 
            return IndexOf(value, startIndex, this.Length - startIndex); 
        }
 
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public extern int IndexOf(char value, int startIndex, int count);

        // Returns the index of the first occurance of any character in value in the current instance. 
        // The search starts at startIndex and runs to endIndex-1. [startIndex,endIndex).
        // 
 
        public int IndexOfAny(char [] anyOf) {
            return IndexOfAny(anyOf,0, this.Length); 
        }

        public int IndexOfAny(char [] anyOf, int startIndex) {
            return IndexOfAny(anyOf, startIndex, this.Length - startIndex); 
        }
 
        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        public extern int IndexOfAny(char [] anyOf, int startIndex, int count);
 

        // Determines the position within this string of the first occurence 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 culture-sensitive, 
        // and the default culture is used.
        // 
        public int IndexOf(String value) { 
            return CultureInfo.CurrentCulture.CompareInfo.IndexOf(this,value);
        } 

        // Determines the position within this string of the first occurence of the specified
        // string, according to the specified search criteria.  The search begins at
        // startIndex, it is case-sensitive and culture-sensitve, and the default culture is used. 
        //
        public int IndexOf(String value, int startIndex) { 
            return CultureInfo.CurrentCulture.CompareInfo.IndexOf(this,value,startIndex); 
        }
 
        // Determines the position within this string of the first occurence of the specified
        // string, according to the specified search criteria.  The search begins at
        // startIndex, ends at endIndex and the default culture is used.
        // 
        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"));
            }
 
            return CultureInfo.CurrentCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.None);
        } 
 
        public int IndexOf(String value, StringComparison comparisonType) {
            return IndexOf(value, 0, this.Length, comparisonType); 
        }

        public int IndexOf(String value, int startIndex, StringComparison comparisonType) {
            return IndexOf(value, startIndex, this.Length - startIndex, comparisonType); 
        }
 
        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")); 

 
            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:
                    return TextInfo.IndexOfStringOrdinalIgnoreCase(this, value, startIndex, count); 

                default:
                    throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
            } 
        }
 
        // Returns the index of the last occurance of value in the current instance. 
        // The search starts at startIndex and runs to endIndex. [startIndex,endIndex].
        // The character at position startIndex is included in the search.  startIndex is the larger 
        // index within the string.
        //
        public int LastIndexOf(char value) {
            return LastIndexOf(value, this.Length-1, this.Length); 
        }
 
        public int LastIndexOf(char value, int startIndex){ 
            return LastIndexOf(value,startIndex,startIndex + 1);
        } 

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public extern int LastIndexOf(char value, int startIndex, int count);
 
        // Returns the index of the last occurance of any character in value in the current instance.
        // The search starts at startIndex and runs to endIndex. [startIndex,endIndex]. 
        // The character at position startIndex is included in the search.  startIndex is the larger 
        // index within the string.
        // 

        public int LastIndexOfAny(char [] anyOf) {
            return LastIndexOfAny(anyOf,this.Length-1,this.Length);
        } 

        public int LastIndexOfAny(char [] anyOf, int startIndex) { 
            return LastIndexOfAny(anyOf,startIndex,startIndex + 1); 
        }
 
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public extern int LastIndexOfAny(char [] anyOf, int startIndex, int count);

 
        // Returns the index of the last occurance of any character in value in the current instance.
        // The search starts at startIndex and runs to endIndex. [startIndex,endIndex]. 
        // The character at position startIndex is included in the search.  startIndex is the larger 
        // index within the string.
        // 
        public int LastIndexOf(String value) {
            return LastIndexOf(value, this.Length-1,this.Length, StringComparison.CurrentCulture);
        }
 
        public int LastIndexOf(String value, int startIndex) {
            return LastIndexOf(value, startIndex, startIndex + 1, StringComparison.CurrentCulture); 
        } 

        public int LastIndexOf(String value, int startIndex, int count) { 
            if (count<0) {
                throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
            }
            return CultureInfo.CurrentCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.None); 
        }
 
        public int LastIndexOf(String value, StringComparison comparisonType) { 
            return LastIndexOf(value, this.Length-1, this.Length, comparisonType);
        } 

        public int LastIndexOf(String value, int startIndex, StringComparison comparisonType) {
            return LastIndexOf(value, startIndex, startIndex + 1, comparisonType);
        } 

        public int LastIndexOf(String value, int startIndex, int count, StringComparison comparisonType) { 
            if (value == null) 
                throw new ArgumentNullException("value");
 
            // Special case for 0 length input strings
            if (this.Length == 0 && (startIndex == -1 || startIndex == 0))
                return (value.Length == 0) ? 0 : -1;
 
            // 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 have 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: 
                    return TextInfo.LastIndexOfStringOrdinalIgnoreCase(this, value, startIndex, count); 

                default: 
                    throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
            }
        }
 
        //
        // 
        public String PadLeft(int totalWidth) { 
            return PadHelper(totalWidth, ' ', false);
        } 

        public String PadLeft(int totalWidth, char paddingChar) {
            return PadHelper(totalWidth, paddingChar, false);
        } 

        public String PadRight(int totalWidth) { 
            return PadHelper(totalWidth, ' ', true); 
        }
 
        public String PadRight(int totalWidth, char paddingChar) {
            return PadHelper(totalWidth, paddingChar, true);
        }
 

        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        private extern String PadHelper(int totalWidth, char paddingChar, bool isRightPadded); 

        // Determines whether a specified string is a prefix of the current instance 
        //
        public Boolean StartsWith(String value) {
            return StartsWith(value, false, null);
        } 

        [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"); 
            }
 
            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) {
                        return false;
                    } 
                    return (nativeCompareOrdinalEx(this, 0, value, 0, value.Length) == 0);
 
                case StringComparison.OrdinalIgnoreCase: 
                    if( this.Length < value.Length) {
                        return false; 
                    }

                    return (TextInfo.CompareOrdinalIgnoreCaseEx(this, 0, value, 0, value.Length) == 0);
 
                default:
                    throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType"); 
            } 
        }
 
        public Boolean StartsWith(String value, Boolean ignoreCase, CultureInfo culture) {
            if (null==value) {
                throw new ArgumentNullException("value");
            } 

            if((object)this == (object)value) { 
                return true; 
            }
            CultureInfo referenceCulture = (culture == null) ? CultureInfo.CurrentCulture : culture; 
            return referenceCulture.CompareInfo.IsPrefix(this, value, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
        }

        // Creates a copy of this string in lower case. 
        public String ToLower() {
            return this.ToLower(CultureInfo.CurrentCulture); 
        } 

        // Creates a copy of this string in lower case.  The culture is set by culture. 
        public String ToLower(CultureInfo culture) {
            if (culture==null) {
                throw new ArgumentNullException("culture");
            } 
            return culture.TextInfo.ToLower(this);
        } 
 
            // Creates a copy of this string in lower case based on invariant culture.
        public String ToLowerInvariant() { 
            return this.ToLower(CultureInfo.InvariantCulture);
        }

        // Creates a copy of this string in upper case. 
        public String ToUpper() {
            return this.ToUpper(CultureInfo.CurrentCulture); 
        } 

        // Creates a copy of this string in upper case.  The culture is set by culture. 
        public String ToUpper(CultureInfo culture) {
            if (culture==null) {
                throw new ArgumentNullException("culture");
            } 
            return culture.TextInfo.ToUpper(this);
        } 
 
        //Creates a copy of this string in upper case based on invariant culture.
        public String ToUpperInvariant() { 
            return this.ToUpper(CultureInfo.InvariantCulture);
        }

        // Returns this string. 
        public override String ToString() {
            return this; 
        } 

        public String ToString(IFormatProvider provider) { 
            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() { 
            return this; 
        }
 

        // Trims the whitespace from both ends of the string.  Whitespace is defined by
        // CharacterInfo.WhitespaceChars.
        // 
        public String Trim() {
            return TrimHelper(WhitespaceChars,TrimBoth); 
        } 

        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;
                    }
                }
            } 

            //Create a new STRINGREF and initialize it from the range determined above. 
            int len = end -start + 1; 
            if (len == this.Length) {
                // Don't allocate a new string is the trimmed string has not changed. 
                return this;
            }
            else {
                if( len == 0) { 
                    return String.Empty;
                } 
                return InternalSubString(start, len, false); 
            }
        } 
        //
        //
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public extern String Insert(int startIndex, String value); 

        // Replaces all instances of oldChar with newChar. 
        // 
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public extern String Replace (char oldChar, char newChar); 

    // 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
        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        public extern String Replace (String oldValue, String newValue);
 
        // 
        //
        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        public extern String Remove(int startIndex, int count);


        // 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")); 
            }
 
            return Substring(0, startIndex); 
        }
 
        public static String Format(String format, Object arg0) {
            return Format(null, format, new Object[] {arg0});
        }
 
        public static String Format(String format, Object arg0, Object arg1) {
            return Format(null, format, new Object[] {arg0, arg1}); 
        } 

        public static String Format(String format, Object arg0, Object arg1, Object arg2) { 
            return Format(null, format, new Object[] {arg0, arg1, arg2});
        }

 
        public static String Format(String format, params Object[] args) {
            return Format(null, format, args); 
        } 

        public static String Format( IFormatProvider provider, String format, params Object[] args) { 
            if (format == null || args == null)
                throw new ArgumentNullException((format==null)?"format":"args");
            StringBuilder sb = new StringBuilder(format.Length + args.Length * 8);
            sb.AppendFormat(provider,format,args); 
            return sb.ToString();
        } 
 
        unsafe public static String Copy (String str) {
            if (str==null) { 
                throw new ArgumentNullException("str");
            }

            int length = str.Length; 

            String result = FastAllocateString(length); 
 
            fixed(char* dest = &result.m_firstChar)
                fixed(char* src = &str.m_firstChar) 
                    wstrcpyPtrAligned(dest, src, length);

            return result;
        } 

        // Used by StringBuilder to avoid data corruption 
        unsafe internal static String InternalCopy (String str) { 
            int length = str.Length;
            String result = FastAllocateString(length); 

            // The underlying's String can changed length is StringBuilder
            fixed(char* dest = &result.m_firstChar)
                fixed(char* src = &str.m_firstChar) 
                    wstrcpyPtrAligned(dest, src, length);
 
            return result; 
        }
 
        public static String Concat(Object arg0) {
            if (arg0==null) {
                return String.Empty;
            } 
            return arg0.ToString();
        } 
 
        public static String Concat(Object arg0, Object arg1) {
            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) {
            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) 
        {
            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
        bool IConvertible.ToBoolean(IFormatProvider provider) {
            return Convert.ToBoolean(this, provider);
        } 

        ///  
        char IConvertible.ToChar(IFormatProvider provider) { 
            return Convert.ToChar(this, provider);
        } 

        /// 
        sbyte IConvertible.ToSByte(IFormatProvider provider) {
            return Convert.ToSByte(this, provider); 
        }
 
        ///  
        byte IConvertible.ToByte(IFormatProvider provider) {
            return Convert.ToByte(this, provider); 
        }

        /// 
        short IConvertible.ToInt16(IFormatProvider provider) { 
            return Convert.ToInt16(this, provider);
        } 
 
        /// 
        ushort IConvertible.ToUInt16(IFormatProvider provider) { 
            return Convert.ToUInt16(this, provider);
        }

        ///  
        int IConvertible.ToInt32(IFormatProvider provider) {
            return Convert.ToInt32(this, provider); 
        } 

        ///  
        uint IConvertible.ToUInt32(IFormatProvider provider) {
            return Convert.ToUInt32(this, provider);
        }
 
        /// 
        long IConvertible.ToInt64(IFormatProvider provider) { 
            return Convert.ToInt64(this, provider); 
        }
 
        /// 
        ulong IConvertible.ToUInt64(IFormatProvider provider) {
            return Convert.ToUInt64(this, provider);
        } 

        ///  
        float IConvertible.ToSingle(IFormatProvider provider) { 
            return Convert.ToSingle(this, provider);
        } 

        /// 
        double IConvertible.ToDouble(IFormatProvider provider) {
            return Convert.ToDouble(this, provider); 
        }
 
        ///  
        Decimal IConvertible.ToDecimal(IFormatProvider provider) {
            return Convert.ToDecimal(this, provider); 
        }

        /// 
        DateTime IConvertible.ToDateTime(IFormatProvider provider) { 
            return Convert.ToDateTime(this, provider);
        } 
 
        /// 
        Object IConvertible.ToType(Type type, IFormatProvider provider) { 
            return Convert.DefaultToType((IConvertible)this, type, provider);
        }

        // Is this a string that can be compared quickly (that is it has only characters > 0x80 
        // and not a - or '
        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        internal extern bool IsFastSort(); 
        // Is this a string that only contains characters < 0x80.
        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        internal extern bool IsAscii();

        ///
        unsafe internal void SetChar(int index, char value) 
        {
#if _DEBUG 
            BCLDebug.Assert(ValidModifiableString(), "Modifiable string must not have highChars flags set"); 
#endif
 
            //Bounds check and then set the actual bit.
            if ((UInt32)index >= (UInt32)Length)
                throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
 
            fixed (char *p = &this.m_firstChar) {
                // Set the character. 
                p[index] = value; 
            }
        } 

#if _DEBUG
        // Only used in debug build. Insure that the HighChar state information for a string is not set as known
        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        private extern bool ValidModifiableString();
#endif 
 
        ///
        unsafe internal void AppendInPlace(char value,int currentLength) 
        {
            BCLDebug.Assert(currentLength < m_arrayLength, "[String.AppendInPlace]currentLength < m_arrayLength");
#if _DEBUG
            BCLDebug.Assert(ValidModifiableString(), "Modifiable string must not have highChars flags set"); 
#endif
 
            fixed (char *p = &this.m_firstChar) 
            {
                // Append the character. 
                p[currentLength] = value;
                currentLength++;
                p[currentLength] = '\0';
                m_stringLength = currentLength; 
            }
        } 
 

        /// 
        unsafe internal void AppendInPlace(char value, int repeatCount, int currentLength)
        {
            int newLength = currentLength + repeatCount;
 
            BCLDebug.Assert(newLength < m_arrayLength, "[String.AppendInPlace]currentLength+repeatCount < m_arrayLength");
#if _DEBUG 
            BCLDebug.Assert(ValidModifiableString(), "Modifiable string must not have highChars flags set"); 
#endif
 
            fixed (char *p = &this.m_firstChar)
            {
                int i;
                for (i=currentLength; i
       internal unsafe void AppendInPlace(String value, int currentLength) { 
            int count = value.Length;
            int newLength = currentLength + count; 
 
            BCLDebug.Assert(value!=null, "[String.AppendInPlace]value!=null");
            BCLDebug.Assert(newLength < this.m_arrayLength, "[String.AppendInPlace]Length is wrong."); 
#if _DEBUG
//            BCLDebug.Assert(ValidModifiableString(), "Modifiable string must not have highChars flags set");
#endif
 
           fixed(char* dest = &this.m_firstChar)
           { 
               fixed(char* src = &value.m_firstChar) { 
                   wstrcpy(dest + currentLength, src, count);
               } 
               dest[newLength] = '\0';
           }
           this.m_stringLength = newLength;
        } 

        internal unsafe void AppendInPlace(String value, int startIndex, int count, int currentLength) { 
            int newLength = currentLength + count; 

            BCLDebug.Assert(value!=null, "[String.AppendInPlace]value!=null"); 
            BCLDebug.Assert(newLength < this.m_arrayLength, "[String.AppendInPlace]newLength < this.m_arrayLength");
            BCLDebug.Assert(count>=0, "[String.AppendInPlace]count>=0");
            BCLDebug.Assert(startIndex>=0, "[String.AppendInPlace]startIndex>=0");
            BCLDebug.Assert(startIndex <= (value.Length - count), "[String.AppendInPlace]startIndex <= (value.Length - count)"); 
#if _DEBUG
            BCLDebug.Assert(ValidModifiableString(), "Modifiable string must not have highChars flags set"); 
#endif 

            fixed(char* dest = &this.m_firstChar) 
            {
                fixed(char* src = &value.m_firstChar)
                    wstrcpy(dest + currentLength, src + startIndex, count);
                dest[newLength] = '\0'; 
            }
            this.m_stringLength = newLength; 
        } 

        internal unsafe void AppendInPlace(char *value, int count,int currentLength) { 
            int newLength = currentLength + count;

            BCLDebug.Assert(value!=null, "[String.AppendInPlace]value!=null");
            BCLDebug.Assert(newLength < this.m_arrayLength, "[String.AppendInPlace]newLength < this.m_arrayLength"); 
            BCLDebug.Assert(count>=0, "[String.AppendInPlace]count>=0");
#if _DEBUG 
            BCLDebug.Assert(ValidModifiableString(), "Modifiable string must not have highChars flags set"); 
#endif
 
            fixed(char *p = &this.m_firstChar)
            {
                wstrcpy(p + currentLength, value, count);
                p[newLength] = '\0'; 
            }
            this.m_stringLength = newLength; 
        } 

 
        ///
        internal unsafe void AppendInPlace(char[] value, int start, int count, int currentLength) {
            int newLength = currentLength + count;
 
            BCLDebug.Assert(value!=null, "[String.AppendInPlace]value!=null");
 
            BCLDebug.Assert(newLength < this.m_arrayLength, "[String.AppendInPlace]Length is wrong."); 
            BCLDebug.Assert(value.Length-count>=start, "[String.AppendInPlace]value.Length-count>=start");
#if _DEBUG 
            BCLDebug.Assert(ValidModifiableString(), "Modifiable string must not have highChars flags set");
#endif

            fixed(char* dest = &this.m_firstChar) 
            {
                // Note: fixed does not like empty arrays 
                if (count > 0) 
                    fixed(char* src = value)
                        wstrcpy(dest + currentLength, src + start, count); 
                dest[newLength] = '\0';
            }
            this.m_stringLength = newLength;
        } 

 
        /// 
        unsafe internal void ReplaceCharInPlace(char oldChar, char newChar, int startIndex, int count,int currentLength) {
            BCLDebug.Assert(startIndex>=0, "[String.ReplaceCharInPlace]startIndex>0"); 
            BCLDebug.Assert(startIndex<=currentLength, "[String.ReplaceCharInPlace]startIndex>=Length");
            BCLDebug.Assert((startIndex<=currentLength-count), "[String.ReplaceCharInPlace]count>0 && startIndex<=currentLength-count");
#if _DEBUG
            BCLDebug.Assert(ValidModifiableString(), "Modifiable string must not have highChars flags set"); 
#endif
 
            int endIndex = startIndex+count; 

            fixed (char *p = &this.m_firstChar) { 
                for (int i=startIndex;i 
        internal static String GetStringForStringBuilder(String value, int capacity) {
            BCLDebug.Assert(value!=null, "[String.GetStringForStringBuilder]value!=null");
            return GetStringForStringBuilder(value,0,value.Length,capacity);
        } 

        /// 
        unsafe internal static String GetStringForStringBuilder(String value, int startIndex, int length, int capacity) { 
            BCLDebug.Assert(value!=null, "[String.GetStringForStringBuilder]value!=null");
            BCLDebug.Assert(capacity>=length,  "[String.GetStringForStringBuilder]capacity>=length"); 

            String newStr = FastAllocateString(capacity);
            if (value.Length==0) {
                newStr.SetLength(0); 
                // already null terminated
                return newStr; 
            } 
            fixed (char* dest = &newStr.m_firstChar)
                fixed (char* src = &value.m_firstChar) { 
                    wstrcpy(dest, src + startIndex, length);
                }
            newStr.SetLength(length);
            // already null terminated 
            return newStr;
        } 
 
        ///
        private unsafe void NullTerminate() { 
            fixed(char *p = &this.m_firstChar) {
                p[m_stringLength] = '\0';
            }
        } 

        /// 
        unsafe internal void ClearPostNullChar() { 
            int newLength = Length+1;
            if (newLength 
        internal void SetLength(int newLength) {
            BCLDebug.Assert(newLength <= m_arrayLength, "newLength<=m_arrayLength"); 
            m_stringLength = newLength;
        }

 

        public CharEnumerator GetEnumerator() { 
            BCLDebug.Perf(false, "Avoid using String's CharEnumerator until C# special cases foreach on String - use the indexed property on String instead."); 
            return new CharEnumerator(this);
        } 

        IEnumerator IEnumerable.GetEnumerator() {
            BCLDebug.Perf(false, "Avoid using String's CharEnumerator until C# special cases foreach on String - use the indexed property on String instead.");
            return new CharEnumerator(this); 
        }
 
        ///  
        IEnumerator IEnumerable.GetEnumerator() {
            BCLDebug.Perf(false, "Avoid using String's CharEnumerator until C# special cases foreach on String - use the indexed property on String instead."); 
            return new CharEnumerator(this);
        }

        internal unsafe void InternalSetCharNoBoundsCheck(int index, char value) { 
            fixed (char *p = &this.m_firstChar) {
                p[index] = value; 
            } 
        }
 
         // Copies the source String (byte buffer) to the destination IntPtr memory allocated with len bytes.
        internal unsafe static void InternalCopy(String src, IntPtr dest,int len)
        {
            if (len == 0) 
                return;
            fixed(char* charPtr = &src.m_firstChar) { 
                byte* srcPtr = (byte*) charPtr; 
                byte* dstPtr = (byte*) dest.ToPointer();
                Buffer.memcpyimpl(srcPtr, dstPtr, len); 
            }
        }

        // memcopies characters inside a String. 
        internal unsafe static void InternalMemCpy(String src, int srcOffset, String dst, int destOffset, int len)
        { 
            if (len == 0) 
                return;
            fixed(char* srcPtr = &src.m_firstChar) { 
                fixed(char* dstPtr = &dst.m_firstChar) {
                    Buffer.memcpyimpl((byte*)(srcPtr + srcOffset), (byte*)(dstPtr + destOffset), len);
                }
            } 
        }
 
 
#if FEATURE_PAL || IA64
        internal unsafe static void revmemcpyimpl(byte* src, byte* dest, int len) { 
            dest += len;
            src += len;
            while (len-- > 0) {
                dest--; 
                src--;
                *dest = *src; 
            } 
        }
 
#else
        internal unsafe static void revmemcpyimpl(byte* src, byte* dest, int len) {
            if (len == 0)
                return; 

            dest += len; 
            src += len; 

            if (((long)src & alignConst) != 0) 
            {
                do{
                    dest--;
                    src--; 
                    len--;
                    *dest = *src; 
                } while (len > 0 && ((long)src & alignConst) != 0); 
            }
 
            if (len >= 16){
                len -= 16;
                do{
                    dest -= (byte*)16; 
                    src -= (byte*)16;
#if AMD64 
                    ((long*)dest)[1] = ((long*)src)[1]; 
                    ((long*)dest)[0] = ((long*)src)[0];
#else 
                    ((int*)dest)[3] = ((int*)src)[3];
                    ((int*)dest)[2] = ((int*)src)[2];
                    ((int*)dest)[1] = ((int*)src)[1];
                    ((int*)dest)[0] = ((int*)src)[0]; 
#endif
                } while ((len -= 16) >= 0); 
            } 
            if ((len & 8) > 0) {
                dest -= (byte*)8; 
                src -= (byte*)8;
#if AMD64
                ((long*)dest)[0] = ((long*)src)[0];
#else 
                ((int*)dest)[1] = ((int*)src)[1];
                ((int*)dest)[0] = ((int*)src)[0]; 
#endif 
            }
            if ((len & 4) > 0) { 
                dest -= (byte*)4;
                src -= (byte*)4;
                ((int*)dest)[0] = ((int*)src)[0];
            } 
            if ((len & 2) != 0) {
                dest -= (byte*)2; 
                src -= (byte*)2; 
                ((short*)dest)[0] = ((short*)src)[0];
            } 
            if ((len & 1) != 0) {
                dest--;
                src--;
                *dest = *src; 
            }
        } 
#endif // FEATURE_PAL || IA64 

 
        internal unsafe void InsertInPlace(int index, String value, int repeatCount, int currentLength, int requiredLength) {
            BCLDebug.Assert(requiredLength  < m_arrayLength, "[String.InsertString] requiredLength  < m_arrayLength");
            BCLDebug.Assert(index >= 0, "index >= 0");
            BCLDebug.Assert(value.Length * repeatCount < m_arrayLength - index, "[String.InsertString] value.Length * repeatCount < m_arrayLength - index"); 
#if _DEBUG
            BCLDebug.Assert(ValidModifiableString(), "Modifiable string must not have highChars flags set"); 
#endif 
              //Copy the old characters over to make room and then insert the new characters.
            fixed(char* srcPtr = &this.m_firstChar) { 
                fixed(char* valuePtr = &value.m_firstChar) {
                   revmemcpyimpl((byte*)(srcPtr + index),(byte*)(srcPtr + index + value.Length * repeatCount), (currentLength - index) * sizeof(char));
                   for (int i=0; i= 0 && index >= 0, "startIndex >= 0 && index >= 0"); 
            BCLDebug.Assert(charCount <= value.Length - startIndex, "[String.InsertInPlace] charCount <= value.Length - startIndex"); 
            BCLDebug.Assert(charCount < m_arrayLength - index, "[String.InsertInPlace]charCount < m_arrayLength - index");
#if _DEBUG 
            BCLDebug.Assert(ValidModifiableString(), "Modifiable string must not have highChars flags set");
#endif
              //Copy the old characters over to make room and then insert the new characters.
            fixed(char* srcPtr = &this.m_firstChar) { 
                fixed(char* valuePtr = value) {
                   revmemcpyimpl((byte*)(srcPtr + index),(byte*)(srcPtr + index + charCount), (currentLength - index) * sizeof(char)); 
                   Buffer.memcpyimpl((byte*)(valuePtr + startIndex), (byte*)(srcPtr + index), charCount * sizeof(char)); 
                }
            } 
            SetLength(requiredLength);
            NullTerminate();
        }
 
        internal unsafe void RemoveInPlace(int index, int charCount, int currentLength) {
            BCLDebug.Assert(index >= 0, "index >= 0"); 
            BCLDebug.Assert(charCount < m_arrayLength - index, "[String.InsertInPlace]charCount < m_arrayLength - index"); 
#if _DEBUG
            BCLDebug.Assert(ValidModifiableString(), "Modifiable string must not have highChars flags set"); 
#endif
            //Move the remaining characters to the left and set the string length.
            String.InternalMemCpy(this, index + charCount, this, index , (currentLength - charCount - index) * sizeof(char));
            int newLength = currentLength - charCount; 
            SetLength(newLength);
            NullTerminate(); //Null terminate. 
        } 
    }
 
    [ComVisible(false)]
    [Flags]
    public enum StringSplitOptions {
        None = 0, 
        RemoveEmptyEntries = 1
    } 
} 


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK