+ internal unsafe int GetCaseInsensitiveHashCode ()
+ {
+ fixed (char * c = this) {
+ char * cc = c;
+ char * end = cc + length - 1;
+ int h = 0;
+ for (;cc < end; cc += 2) {
+ h = (h << 5) - h + Char.ToUpperInvariant (*cc);
+ h = (h << 5) - h + Char.ToUpperInvariant (cc [1]);
+ }
+ ++end;
+ if (cc < end)
+ h = (h << 5) - h + Char.ToUpperInvariant (*cc);
+ return h;
+ }
+ }
+
+ // Certain constructors are redirected to CreateString methods with
+ // matching argument list. The this pointer should not be used.
+#pragma warning disable 169
+ private unsafe String CreateString (sbyte* value)
+ {
+ if (value == null)
+ return String.Empty;
+
+ byte* bytes = (byte*) value;
+ int length = 0;
+
+ try {
+ while (bytes++ [0] != 0)
+ length++;
+ } catch (NullReferenceException) {
+ throw new ArgumentOutOfRangeException ("ptr", "Value does not refer to a valid string.");
+#if NET_2_0
+ } catch (AccessViolationException) {
+ throw new ArgumentOutOfRangeException ("ptr", "Value does not refer to a valid string.");
+#endif
+ }
+
+ return CreateString (value, 0, length, null);
+ }
+
+ private unsafe String CreateString (sbyte* value, int startIndex, int length)
+ {
+ return CreateString (value, startIndex, length, null);
+ }
+
+ private unsafe String CreateString (sbyte* value, int startIndex, int length, Encoding enc)
+ {
+ if (length < 0)
+ throw new ArgumentOutOfRangeException ("length", "Non-negative number required.");
+ if (startIndex < 0)
+ throw new ArgumentOutOfRangeException ("startIndex", "Non-negative number required.");
+ if (value + startIndex < value)
+ throw new ArgumentOutOfRangeException ("startIndex", "Value, startIndex and length do not refer to a valid string.");
+
+ bool isDefaultEncoding;
+
+ if (isDefaultEncoding = (enc == null)) {
+#if NET_2_0
+ if (value == null)
+ throw new ArgumentNullException ("value");
+ if (length == 0)
+#else
+ if (value == null || length == 0)
+#endif
+ return String.Empty;
+
+ enc = Encoding.Default;
+ }
+
+ byte [] bytes = new byte [length];
+
+ if (length != 0)
+ fixed (byte* bytePtr = bytes)
+ try {
+ memcpy (bytePtr, (byte*) (value + startIndex), length);
+ } catch (NullReferenceException) {
+#if !NET_2_0
+ if (!isDefaultEncoding)
+ throw;
+#endif
+
+ throw new ArgumentOutOfRangeException ("ptr", "Value, startIndex and length do not refer to a valid string.");
+#if NET_2_0
+ } catch (AccessViolationException) {
+ if (!isDefaultEncoding)
+ throw;
+
+ throw new ArgumentOutOfRangeException ("value", "Value, startIndex and length do not refer to a valid string.");
+#endif
+ }
+
+ // GetString () is called even when length == 0
+ 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) {
+ CharCopy (dest, value, i);
+ }
+ }
+ 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) {
+ CharCopy (dest, value + startIndex, length);
+ }
+ return result;
+ }
+
+ unsafe string CreateString (char [] val, int startIndex, int length)
+ {
+ if (val == null)
+ throw new ArgumentNullException ("value");
+ if (startIndex < 0)
+ throw new ArgumentOutOfRangeException ("startIndex", "Cannot be negative.");
+ if (length < 0)
+ throw new ArgumentOutOfRangeException ("length", "Cannot be negative.");
+ if (startIndex > val.Length - length)
+ throw new ArgumentOutOfRangeException ("startIndex", "Cannot be negative, and should be less than length of string.");
+ if (length == 0)
+ return string.Empty;
+
+ string result = InternalAllocateStr (length);
+
+ fixed (char *dest = result, src = val) {
+ CharCopy (dest, src + startIndex, length);
+ }
+ 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) {
+ CharCopy (dest, src, val.Length);
+ }
+ 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;
+ }
+#pragma warning restore 169
+
+ /* helpers used by the runtime as well as above or eslewhere in corlib */
+ internal static unsafe void memset (byte *dest, int val, int len)
+ {
+ if (len < 8) {
+ while (len != 0) {
+ *dest = (byte)val;
+ ++dest;
+ --len;
+ }
+ return;
+ }
+ if (val != 0) {
+ val = val | (val << 8);
+ val = val | (val << 16);
+ }
+ // align to 4
+ int rest = (int)dest & 3;
+ if (rest != 0) {
+ rest = 4 - rest;
+ len -= rest;
+ do {
+ *dest = (byte)val;
+ ++dest;
+ --rest;
+ } while (rest != 0);
+ }
+ while (len >= 16) {
+ ((int*)dest) [0] = val;
+ ((int*)dest) [1] = val;
+ ((int*)dest) [2] = val;
+ ((int*)dest) [3] = val;
+ dest += 16;
+ len -= 16;
+ }
+ while (len >= 4) {
+ ((int*)dest) [0] = val;
+ dest += 4;
+ len -= 4;
+ }
+ // tail bytes
+ while (len > 0) {
+ *dest = (byte)val;
+ dest++;
+ len--;
+ }
+ }
+
+ static unsafe void memcpy4 (byte *dest, byte *src, int size) {
+ /*while (size >= 32) {
+ // using long is better than int and slower than double
+ // FIXME: enable this only on correct alignment or on platforms
+ // that can tolerate unaligned reads/writes of doubles
+ ((double*)dest) [0] = ((double*)src) [0];
+ ((double*)dest) [1] = ((double*)src) [1];
+ ((double*)dest) [2] = ((double*)src) [2];
+ ((double*)dest) [3] = ((double*)src) [3];
+ dest += 32;
+ src += 32;
+ size -= 32;
+ }*/
+ while (size >= 16) {
+ ((int*)dest) [0] = ((int*)src) [0];
+ ((int*)dest) [1] = ((int*)src) [1];
+ ((int*)dest) [2] = ((int*)src) [2];
+ ((int*)dest) [3] = ((int*)src) [3];
+ dest += 16;
+ src += 16;
+ size -= 16;
+ }
+ while (size >= 4) {
+ ((int*)dest) [0] = ((int*)src) [0];
+ dest += 4;
+ src += 4;
+ size -= 4;
+ }
+ while (size > 0) {
+ ((byte*)dest) [0] = ((byte*)src) [0];
+ dest += 1;
+ src += 1;
+ --size;
+ }
+ }
+ static unsafe void memcpy2 (byte *dest, byte *src, int size) {
+ while (size >= 8) {
+ ((short*)dest) [0] = ((short*)src) [0];
+ ((short*)dest) [1] = ((short*)src) [1];
+ ((short*)dest) [2] = ((short*)src) [2];
+ ((short*)dest) [3] = ((short*)src) [3];
+ dest += 8;
+ src += 8;
+ size -= 8;
+ }
+ while (size >= 2) {
+ ((short*)dest) [0] = ((short*)src) [0];
+ dest += 2;
+ src += 2;
+ size -= 2;
+ }
+ if (size > 0)
+ ((byte*)dest) [0] = ((byte*)src) [0];
+ }
+ static unsafe void memcpy1 (byte *dest, byte *src, int size) {
+ while (size >= 8) {
+ ((byte*)dest) [0] = ((byte*)src) [0];
+ ((byte*)dest) [1] = ((byte*)src) [1];
+ ((byte*)dest) [2] = ((byte*)src) [2];
+ ((byte*)dest) [3] = ((byte*)src) [3];
+ ((byte*)dest) [4] = ((byte*)src) [4];
+ ((byte*)dest) [5] = ((byte*)src) [5];
+ ((byte*)dest) [6] = ((byte*)src) [6];
+ ((byte*)dest) [7] = ((byte*)src) [7];
+ dest += 8;
+ src += 8;
+ size -= 8;
+ }
+ while (size >= 2) {
+ ((byte*)dest) [0] = ((byte*)src) [0];
+ ((byte*)dest) [1] = ((byte*)src) [1];
+ dest += 2;
+ src += 2;
+ size -= 2;
+ }
+ if (size > 0)
+ ((byte*)dest) [0] = ((byte*)src) [0];
+ }
+
+ internal static unsafe void memcpy (byte *dest, byte *src, int size) {
+ // FIXME: if pointers are not aligned, try to align them
+ // so a faster routine can be used. Handle the case where
+ // the pointers can't be reduced to have the same alignment
+ // (just ignore the issue on x86?)
+ if ((((int)dest | (int)src) & 3) != 0) {
+ if (((int)dest & 1) != 0 && ((int)src & 1) != 0 && size >= 1) {
+ dest [0] = src [0];
+ ++dest;
+ ++src;
+ --size;
+ }
+ if (((int)dest & 2) != 0 && ((int)src & 2) != 0 && size >= 2) {
+ ((short*)dest) [0] = ((short*)src) [0];
+ dest += 2;
+ src += 2;
+ size -= 2;
+ }
+ if ((((int)dest | (int)src) & 1) != 0) {
+ memcpy1 (dest, src, size);
+ return;
+ }
+ if ((((int)dest | (int)src) & 2) != 0) {
+ memcpy2 (dest, src, size);
+ return;
+ }
+ }
+ memcpy4 (dest, src, size);
+ }
+
+ internal static unsafe void CharCopy (char *dest, char *src, int count) {
+ // Same rules as for memcpy, but with the premise that
+ // chars can only be aligned to even addresses if their
+ // enclosing types are correctly aligned
+ if ((((int)(byte*)dest | (int)(byte*)src) & 3) != 0) {
+ if (((int)(byte*)dest & 2) != 0 && ((int)(byte*)src & 2) != 0 && count > 0) {
+ ((short*)dest) [0] = ((short*)src) [0];
+ dest++;
+ src++;
+ count--;
+ }
+ if ((((int)(byte*)dest | (int)(byte*)src) & 2) != 0) {
+ memcpy2 ((byte*)dest, (byte*)src, count * 2);
+ return;
+ }
+ }
+ memcpy4 ((byte*)dest, (byte*)src, count * 2);
+ }
+
+ internal static unsafe void CharCopyReverse (char *dest, char *src, int count)
+ {
+ dest += count;
+ src += count;
+ for (int i = count; i > 0; i--) {
+ dest--;
+ src--;
+ *dest = *src;
+ }
+ }
+
+ internal static unsafe void CharCopy (String target, int targetIndex, String source, int sourceIndex, int count)
+ {
+ fixed (char* dest = target, src = source)
+ CharCopy (dest + targetIndex, src + sourceIndex, count);
+ }
+
+ internal static unsafe void CharCopy (String target, int targetIndex, Char[] source, int sourceIndex, int count)
+ {
+ fixed (char* dest = target, src = source)
+ CharCopy (dest + targetIndex, src + sourceIndex, count);
+ }
+
+ // Use this method if you cannot block copy from left to right (e.g. because you are coping within the same string)
+ internal static unsafe void CharCopyReverse (String target, int targetIndex, String source, int sourceIndex, int count)
+ {
+ fixed (char* dest = target, src = source)
+ CharCopyReverse (dest + targetIndex, src + sourceIndex, count);
+ }
+