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)
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)]
public unsafe String Substring (int startIndex)
{
+ if (startIndex == 0)
+ return this;
+
if (startIndex < 0 || startIndex > this.length)
throw new ArgumentOutOfRangeException ("startIndex");
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)
return 0;
else
return -1;
- }
- else if (strB == null) {
+ } else if (strB == null) {
return 1;
}
{
if (anyOf == null)
throw new ArgumentNullException ("anyOf");
+ if (this.length == 0)
+ return -1;
return InternalIndexOfAny (anyOf, 0, this.length);
}
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)
{
- return IndexOf (value, 0, value.Length, comparison);
+ return IndexOf (value, 0, this.Length, comparison);
}
public int IndexOf (string value, int startIndex, StringComparison comparison)
{
- return IndexOf (value, startIndex, value.Length - startIndex, comparison);
+ return IndexOf (value, startIndex, this.Length - startIndex, comparison);
}
public int IndexOf (string value, int startIndex, int count, StringComparison comparison)
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)
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 */
{
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)
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 */
throw new ArgumentOutOfRangeException ("startIndex - count + 1 < 0");
if (value.Length == 0)
- return 0;
+ return startIndex;
if (startIndex == 0 && this.length == 0)
return -1;
}
#if NET_2_0
+ [ComVisible (false)]
public bool StartsWith (string value, StringComparison comparisonType)
{
switch (comparisonType) {
}
}
+ [ComVisible (false)]
public bool EndsWith (string value, StringComparison comparisonType)
{
switch (comparisonType) {
}
/* 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 */
#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) {
}
}
+ 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.
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)
{
[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);
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);