remove warning
[mono.git] / mcs / class / corlib / System / String.cs
index f8188703f0f287b7499fdb3ae78b4e7cd745f006..df5b4451f3e772ea0dca6578dce2014ac27318ec 100644 (file)
@@ -216,12 +216,12 @@ namespace System
                        if (count == 1) 
                                return new String[1] { ToString() };
 
-                       return InternalSplit (separator, count);
+                       return InternalSplit (separator, count, 0);
                }
 
 #if NET_2_0
                [ComVisible (false)]
-               [MonoTODO]
+               [MonoDocumentationNote ("code should be moved to managed")]
                public String[] Split (char[] separator, int count, StringSplitOptions options)
                {
                        if (separator == null || separator.Length == 0)
@@ -232,28 +232,10 @@ namespace System
                        if ((options != StringSplitOptions.None) && (options != StringSplitOptions.RemoveEmptyEntries))
                                throw new ArgumentException ("options must be one of the values in the StringSplitOptions enumeration", "options");
 
-                       bool removeEmpty = (options & StringSplitOptions.RemoveEmptyEntries) == StringSplitOptions.RemoveEmptyEntries;
+                       if (count == 0)
+                               return new string [0];
 
-                       if (!removeEmpty)
-                               return Split (separator, count);
-                       else {
-                               /* FIXME: Optimize this */
-                               String[] res = Split (separator, count);
-                               int n = 0;
-                               for (int i = 0; i < res.Length; ++i)
-                                       if (res [i] == String.Empty)
-                                               n ++;
-                               if (n > 0) {
-                                       String[] arr = new String [res.Length - n];
-                                       int pos = 0;
-                                       for (int i = 0; i < res.Length; ++i)
-                                               if (res [i] != String.Empty)
-                                                       arr [pos ++] = res [i];
-                                       return arr;
-                               }
-                               else
-                                       return res;
-                       }
+                       return InternalSplit (separator, count, (int)options);
                }
 
                [ComVisible (false)]
@@ -343,6 +325,9 @@ namespace System
 
                public unsafe String Substring (int startIndex)
                {
+                       if (startIndex == 0)
+                               return this;
+
                        if (startIndex < 0 || startIndex > this.length)
                                throw new ArgumentOutOfRangeException ("startIndex");
 
@@ -579,9 +564,28 @@ namespace System
                        return Compare (this, strB, false);
                }
 
-               public static int CompareOrdinal (String strA, String strB)
+               public static unsafe int CompareOrdinal (String strA, String strB)
                {
-                       return CompareOrdinal (strA, strB, CompareOptions.Ordinal);
+                       if (strA == null) {
+                               if (strB == null)
+                                       return 0;
+                               else
+                                       return -1;
+                       } else if (strB == null) {
+                               return 1;
+                       }
+                       fixed (char* aptr = strA, bptr = strB) {
+                               char* ap = aptr;
+                               char* end = ap + Math.Min (strA.Length, strB.Length);
+                               char* bp = bptr;
+                               while (ap < end) {
+                                       if (*ap != *bp)
+                                               return *ap - *bp;
+                                       ap++;
+                                       bp++;
+                               }
+                               return strA.Length - strB.Length;
+                       }
                }
 
                internal static int CompareOrdinal (String strA, String strB, CompareOptions options)
@@ -591,8 +595,7 @@ namespace System
                                        return 0;
                                else
                                        return -1;
-                       }
-                       else if (strB == null) {
+                       } else if (strB == null) {
                                return 1;
                        }
 
@@ -663,6 +666,8 @@ namespace System
                {
                        if (anyOf == null)
                                throw new ArgumentNullException ("anyOf");
+                       if (this.length == 0)
+                               return -1;
 
                        return InternalIndexOfAny (anyOf, 0, this.length);
                }
@@ -692,6 +697,57 @@ namespace System
                        return InternalIndexOfAny (anyOf, startIndex, count);
                }
 
+               unsafe int InternalIndexOfAny (char[] anyOf, int startIndex, int count)
+               {
+                       if (anyOf.Length == 0)
+                               return -1;
+
+                       if (anyOf.Length == 1)
+                               return IndexOfImpl(anyOf[0], startIndex, count);
+
+                       fixed (char* any = anyOf) {
+                               int highest = *any;
+                               int lowest = *any;
+
+                               char* end_any_ptr = any + anyOf.Length;
+                               char* any_ptr = any;
+                               while (++any_ptr != end_any_ptr) {
+                                       if (*any_ptr > highest) {
+                                               highest = *any_ptr;
+                                               continue;
+                                       }
+
+                                       if (*any_ptr < lowest)
+                                               lowest = *any_ptr;
+                               }
+
+                               fixed (char* start = &start_char) {
+                                       char* ptr = start + startIndex;
+                                       char* end_ptr = ptr + count;
+
+                                       while (ptr != end_ptr) {
+                                               if (*ptr > highest || *ptr < lowest) {
+                                                       ptr++;
+                                                       continue;
+                                               }
+
+                                               if (*ptr == *any)
+                                                       return (int)(ptr - start);
+
+                                               any_ptr = any;
+                                               while (++any_ptr != end_any_ptr) {
+                                                       if (*ptr == *any_ptr)
+                                                               return (int)(ptr - start);
+                                               }
+
+                                               ptr++;
+                                       }
+                               }
+                       }
+                       return -1;
+               }
+
+
 #if NET_2_0
                public int IndexOf (string value, StringComparison comparison)
                {
@@ -754,7 +810,10 @@ namespace System
 
                public int IndexOf (char value)
                {
-                       return IndexOf (value, 0, this.length);
+                       if (this.length == 0)
+                               return -1;
+
+                       return IndexOfImpl (value, 0, this.length);
                }
 
                public int IndexOf (String value)
@@ -786,11 +845,48 @@ namespace System
                        if ((startIndex == 0 && this.length == 0) || (startIndex == this.length) || (count == 0))
                                return -1;
 
-                       for (int pos = startIndex; pos < startIndex + count; pos++) {
-                               if (this[pos] == value)
-                                       return(pos);
+                       return IndexOfImpl (value, startIndex, count);
+               }
+
+               unsafe int IndexOfImpl (char value, int startIndex, int count)
+               {
+                       // It helps JIT compiler to optimize comparison
+                       int value_32 = (int)value;
+
+                       fixed (char* start = &start_char) {
+                               char* ptr = start + startIndex;
+                               char* end_ptr = ptr + (count >> 3 << 3);
+
+                               while (ptr != end_ptr) {
+                                       if (*ptr == value_32)
+                                               return (int)(ptr - start);
+                                       if (ptr[1] == value_32)
+                                               return (int)(ptr - start + 1);
+                                       if (ptr[2] == value_32)
+                                               return (int)(ptr - start + 2);
+                                       if (ptr[3] == value_32)
+                                               return (int)(ptr - start + 3);
+                                       if (ptr[4] == value_32)
+                                               return (int)(ptr - start + 4);
+                                       if (ptr[5] == value_32)
+                                               return (int)(ptr - start + 5);
+                                       if (ptr[6] == value_32)
+                                               return (int)(ptr - start + 6);
+                                       if (ptr[7] == value_32)
+                                               return (int)(ptr - start + 7);
+
+                                       ptr += 8;
+                               }
+
+                               end_ptr += count & 0x07;
+                               while (ptr != end_ptr) {
+                                       if (*ptr == value_32)
+                                               return (int)(ptr - start);
+
+                                       ptr++;
+                               }
+                               return -1;
                        }
-                       return -1;
                }
 
                /* But this one is culture-sensitive */
@@ -862,8 +958,8 @@ namespace System
                {
                        if (this.length == 0)
                                return -1;
-                       else
-                               return LastIndexOf (value, this.length - 1, this.length);
+                       
+                       return LastIndexOfImpl (value, this.length - 1, this.length);
                }
 
                public int LastIndexOf (String value)
@@ -904,11 +1000,49 @@ namespace System
                        if (startIndex - count + 1 < 0)
                                throw new ArgumentOutOfRangeException ("startIndex - count + 1 < 0");
 
-                       for(int pos = startIndex; pos > startIndex - count; pos--) {
-                               if (this [pos] == value)
-                                       return pos;
+                       return LastIndexOfImpl (value, startIndex, count);
+               }
+
+               /* This method is culture-insensitive */
+               unsafe int LastIndexOfImpl (char value, int startIndex, int count)
+               {
+                       // It helps JIT compiler to optimize comparison
+                       int value_32 = (int)value;
+
+                       fixed (char* start = &start_char) {
+                               char* ptr = start + startIndex;
+                               char* end_ptr = ptr - (count >> 3 << 3);
+
+                               while (ptr != end_ptr) {
+                                       if (*ptr == value_32)
+                                               return (int)(ptr - start);
+                                       if (ptr[-1] == value_32)
+                                               return (int)(ptr - start) - 1;
+                                       if (ptr[-2] == value_32)
+                                               return (int)(ptr - start) - 2;
+                                       if (ptr[-3] == value_32)
+                                               return (int)(ptr - start) - 3;
+                                       if (ptr[-4] == value_32)
+                                               return (int)(ptr - start) - 4;
+                                       if (ptr[-5] == value_32)
+                                               return (int)(ptr - start) - 5;
+                                       if (ptr[-6] == value_32)
+                                               return (int)(ptr - start) - 6;
+                                       if (ptr[-7] == value_32)
+                                               return (int)(ptr - start) - 7;
+
+                                       ptr -= 8;
+                               }
+
+                               end_ptr -= count & 0x07;
+                               while (ptr != end_ptr) {
+                                       if (*ptr == value_32)
+                                               return (int)(ptr - start);
+
+                                       ptr--;
+                               }
+                               return -1;
                        }
-                       return -1;
                }
 
                /* But this one is culture-sensitive */
@@ -1040,6 +1174,7 @@ namespace System
                }
 
 #if NET_2_0
+               [ComVisible (false)]
                public bool StartsWith (string value, StringComparison comparisonType)
                {
                        switch (comparisonType) {
@@ -1060,6 +1195,7 @@ namespace System
                        }
                }
 
+               [ComVisible (false)]
                public bool EndsWith (string value, StringComparison comparisonType)
                {
                        switch (comparisonType) {
@@ -1098,9 +1234,38 @@ namespace System
                }
 
                /* This method is culture insensitive */
-               public String Replace (char oldChar, char newChar)
+               public unsafe String Replace (char oldChar, char newChar)
                {
-                       return InternalReplace (oldChar, newChar);
+                       if (this.length == 0 || oldChar == newChar)
+                               return this;
+
+                       int start_pos = IndexOfImpl (oldChar, 0, this.length);
+                       if (start_pos == -1)
+                               return this;
+
+                       if (start_pos < 4)
+                               start_pos = 0;
+
+                       string tmp = InternalAllocateStr(length);
+                       fixed (char* dest = tmp, src = &start_char) {
+                               if (start_pos != 0)
+                                       memcpy((byte*)dest, (byte*)src, start_pos * 2);
+
+                               char* end_ptr = dest + length;
+                               char* dest_ptr = dest + start_pos;
+                               char* src_ptr = src + start_pos;
+
+                               while (dest_ptr != end_ptr) {
+                                       if (*src_ptr == oldChar)
+                                               *dest_ptr = newChar;
+                                       else
+                                               *dest_ptr = *src_ptr;
+
+                                       ++src_ptr;
+                                       ++dest_ptr;
+                               }
+                       }
+                       return tmp;
                }
 
                /* This method is culture sensitive */
@@ -1880,6 +2045,7 @@ namespace System
 #if NET_2_0
                [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
 #endif
+               // When modifying it, GetCaseInsensitiveHashCode() should be modified as well.
                public unsafe override int GetHashCode ()
                {
                        fixed (char * c = this) {
@@ -1897,6 +2063,24 @@ namespace System
                        }
                }
 
+               internal unsafe int GetCaseInsensitiveHashCode ()
+               {
+                       TextInfo ti = CultureInfo.InvariantCulture.TextInfo;
+                       fixed (char * c = this) {
+                               char * cc = c;
+                               char * end = cc + length - 1;
+                               int h = 0;
+                               for (;cc < end; cc += 2) {
+                                       h = (h << 5) - h + ti.ToUpper (*cc);
+                                       h = (h << 5) - h + ti.ToUpper (cc [1]);
+                               }
+                               ++end;
+                               if (cc < end)
+                                       h = (h << 5) - h + ti.ToUpper (*cc);
+                               return h;
+                       }
+               }
+
                // Certain constructors are redirected to CreateString methods with
                // matching argument list. The this pointer should not be used.
 
@@ -1977,6 +2161,98 @@ namespace System
                        return enc.GetString (bytes);
                }
 
+               unsafe string CreateString (char *value)
+               {
+                       if (value == null)
+                               return string.Empty;
+                       char *p = value;
+                       int i = 0;
+                       while (*p != 0) {
+                               ++i;
+                               ++p;
+                       }
+                       string result = InternalAllocateStr (i);
+
+                       if (i != 0) {
+                               fixed (char *dest = result) {
+                                       memcpy ((byte*)dest, (byte*)value, i * 2);
+                               }
+                       }
+                       return result;
+               }
+
+               unsafe string CreateString (char *value, int startIndex, int length)
+               {
+                       if (length == 0)
+                               return string.Empty;
+                       if (value == null)
+                               throw new ArgumentNullException ("value");
+                       if (startIndex < 0)
+                               throw new ArgumentOutOfRangeException ("startIndex");
+                       if (length < 0)
+                               throw new ArgumentOutOfRangeException ("length");
+
+                       string result = InternalAllocateStr (length);
+
+                       fixed (char *dest = result) {
+                               memcpy ((byte*)dest, (byte*)(value + startIndex), length * 2);
+                       }
+                       return result;
+               }
+
+               unsafe string CreateString (char [] val, int startIndex, int length)
+               {
+                       if (val == null)
+                               throw new ArgumentNullException ("val");
+                       if (startIndex < 0)
+                               throw new ArgumentOutOfRangeException ("startIndex");
+                       if (length < 0)
+                               throw new ArgumentOutOfRangeException ("length");
+                       if (startIndex > val.Length - length)
+                               throw new ArgumentOutOfRangeException ("Out of range");
+                       if (length == 0)
+                               return string.Empty;
+
+                       string result = InternalAllocateStr (length);
+
+                       fixed (char *dest = result, src = val) {
+                               memcpy ((byte*)dest, (byte*)(src + startIndex), length * 2);
+                       }
+                       return result;
+               }
+
+               unsafe string CreateString (char [] val)
+               {
+                       if (val == null)
+                               return string.Empty;
+                       if (val.Length == 0)
+                               return string.Empty;
+                       string result = InternalAllocateStr (val.Length);
+
+                       fixed (char *dest = result, src = val) {
+                               memcpy ((byte*)dest, (byte*)src, val.Length * 2);
+                       }
+                       return result;
+               }
+
+               unsafe string CreateString (char c, int count)
+               {
+                       if (count < 0)
+                               throw new ArgumentOutOfRangeException ("count");
+                       if (count == 0)
+                               return string.Empty;
+                       string result = InternalAllocateStr (count);
+                       fixed (char *dest = result) {
+                               char *p = dest;
+                               char *end = p + count;
+                               while (p < end) {
+                                       *p = c;
+                                       p++;
+                               }
+                       }
+                       return result;
+               }
+
                /* helpers used by the runtime as well as above or eslewhere in corlib */
                internal static unsafe void memset (byte *dest, int val, int len)
                {
@@ -2160,9 +2436,6 @@ namespace System
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                private extern static string InternalJoin (string separator, string[] value, int sIndex, int count);
 
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               private extern String InternalReplace (char oldChar, char newChar);
-
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                private extern String InternalReplace (String oldValue, string newValue, CompareInfo comp);
 
@@ -2170,14 +2443,11 @@ namespace System
                private extern void InternalCopyTo (int sIndex, char[] dest, int destIndex, int count);
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               private extern String[] InternalSplit (char[] separator, int count);
+               private extern String[] InternalSplit (char[] separator, int count, int options);
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                private extern String InternalTrim (char[] chars, int typ);
 
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               private extern int InternalIndexOfAny (char [] arr, int sIndex, int count);
-
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                private extern int InternalLastIndexOfAny (char [] anyOf, int sIndex, int count);