[corlib] Add missing file
authorMarek Safar <marek.safar@gmail.com>
Wed, 25 Mar 2015 16:26:27 +0000 (17:26 +0100)
committerMarek Safar <marek.safar@gmail.com>
Wed, 25 Mar 2015 16:26:47 +0000 (17:26 +0100)
mcs/class/corlib/ReferenceSources/String.cs [new file with mode: 0644]

diff --git a/mcs/class/corlib/ReferenceSources/String.cs b/mcs/class/corlib/ReferenceSources/String.cs
new file mode 100644 (file)
index 0000000..d4cec69
--- /dev/null
@@ -0,0 +1,766 @@
+//
+// System.String.cs
+//
+// Authors:
+//   Patrik Torstensson
+//   Jeffrey Stedfast (fejj@ximian.com)
+//   Dan Lewis (dihlewis@yahoo.co.uk)
+//   Sebastien Pouliot  <sebastien@ximian.com>
+//   Marek Safar (marek.safar@seznam.cz)
+//   Andreas Nahr (Classdevelopment@A-SoftTech.com)
+//
+// (C) 2001 Ximian, Inc.  http://www.ximian.com
+// Copyright (C) 2004-2005 Novell (http://www.novell.com)
+// Copyright (c) 2012 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//
+
+using System.Runtime.CompilerServices;
+using System.Text;
+
+namespace System
+{
+       partial class String
+       {
+               public int Length {
+                       get {
+                               return m_stringLength;
+                       }
+               }
+
+               internal static unsafe int CompareOrdinalUnchecked (String strA, int indexA, int lenA, String strB, int indexB, int lenB)
+               {
+                       if (strA == null) {
+                               return strB == null ? 0 : -1;
+                       }
+                       if (strB == null) {
+                               return 1;
+                       }
+                       int lengthA = Math.Min (lenA, strA.m_stringLength - indexA);
+                       int lengthB = Math.Min (lenB, strB.m_stringLength - indexB);
+
+                       if (lengthA == lengthB && indexA == indexB && Object.ReferenceEquals (strA, strB))
+                               return 0;
+
+                       fixed (char* aptr = strA, bptr = strB) {
+                               char* ap = aptr + indexA;
+                               char* end = ap + Math.Min (lengthA, lengthB);
+                               char* bp = bptr + indexB;
+                               while (ap < end) {
+                                       if (*ap != *bp)
+                                               return *ap - *bp;
+                                       ap++;
+                                       bp++;
+                               }
+                               return lengthA - lengthB;
+                       }
+               }
+
+               public int IndexOf (char value, int startIndex, int count)
+               {
+                       if (startIndex < 0 || startIndex > this.m_stringLength)
+                               throw new ArgumentOutOfRangeException ("startIndex", "Cannot be negative and must be< 0");
+                       if (count < 0)
+                               throw new ArgumentOutOfRangeException ("count", "< 0");
+                       if (startIndex > this.m_stringLength - count)
+                               throw new ArgumentOutOfRangeException ("count", "startIndex + count > this.m_stringLength");
+
+                       if ((startIndex == 0 && this.m_stringLength == 0) || (startIndex == this.m_stringLength) || (count == 0))
+                               return -1;
+
+                       return IndexOfUnchecked (value, startIndex, count);
+               }
+
+               internal unsafe int IndexOfUnchecked (char value, int startIndex, int count)
+               {
+                       // It helps JIT compiler to optimize comparison
+                       int value_32 = (int)value;
+
+                       fixed (char* start = &m_firstChar) {
+                               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;
+                       }
+               }
+
+               internal unsafe int IndexOfUnchecked (string value, int startIndex, int count)
+               {
+                       int valueLen = value.Length;
+                       if (count < valueLen)
+                               return -1;
+
+                       if (valueLen <= 1) {
+                               if (valueLen == 1)
+                                       return IndexOfUnchecked (value[0], startIndex, count);
+                               return startIndex;
+                       }
+
+                       fixed (char* thisptr = &m_firstChar, valueptr = value) {
+                               char* ap = thisptr + startIndex;
+                               char* thisEnd = ap + count - valueLen + 1;
+                               while (ap != thisEnd) {
+                                       if (*ap == *valueptr) {
+                                               for (int i = 1; i < valueLen; i++) {
+                                                       if (ap[i] != valueptr[i])
+                                                               goto NextVal;
+                                               }
+                                               return (int)(ap - thisptr);
+                                       }
+                                       NextVal:
+                                       ap++;
+                               }
+                       }
+                       return -1;
+               }
+
+               public int IndexOfAny (char [] anyOf, int startIndex, int count)
+               {
+                       if (anyOf == null)
+                               throw new ArgumentNullException ();
+                       if (startIndex < 0 || startIndex > this.m_stringLength)
+                               throw new ArgumentOutOfRangeException ();
+                       if (count < 0 || startIndex > this.m_stringLength - count)
+                               throw new ArgumentOutOfRangeException ("count", "Count cannot be negative, and startIndex + count must be less than m_stringLength of the string.");
+
+                       return IndexOfAnyUnchecked (anyOf, startIndex, count);
+               }               
+
+               unsafe int IndexOfAnyUnchecked (char[] anyOf, int startIndex, int count)
+               {
+                       if (anyOf.Length == 0)
+                               return -1;
+
+                       if (anyOf.Length == 1)
+                               return IndexOfUnchecked (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 = &m_firstChar) {
+                                       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;
+               }
+
+               public int LastIndexOf (char value, int startIndex, int count)
+               {
+                       if (this.m_stringLength == 0)
+                               return -1;
+                       // >= for char (> for string)
+                       if ((startIndex < 0) || (startIndex >= this.Length))
+                               throw new ArgumentOutOfRangeException ("startIndex", "< 0 || >= this.Length");
+                       if ((count < 0) || (count > this.Length))
+                               throw new ArgumentOutOfRangeException ("count", "< 0 || > this.Length");
+                       if (startIndex - count + 1 < 0)
+                               throw new ArgumentOutOfRangeException ("startIndex - count + 1 < 0");
+
+                       return LastIndexOfUnchecked (value, startIndex, count);
+               }
+
+               internal unsafe int LastIndexOfUnchecked (char value, int startIndex, int count)
+               {
+                       // It helps JIT compiler to optimize comparison
+                       int value_32 = (int)value;
+
+                       fixed (char* start = &m_firstChar) {
+                               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;
+                       }
+               }
+
+               public int LastIndexOfAny (char [] anyOf, int startIndex, int count)
+               {
+                       if (anyOf == null) 
+                               throw new ArgumentNullException ();
+                       if (this.m_stringLength == 0)
+                               return -1;
+
+                       if ((startIndex < 0) || (startIndex >= this.Length))
+                               throw new ArgumentOutOfRangeException ("startIndex", "< 0 || > this.Length");
+                       if ((count < 0) || (count > this.Length))
+                               throw new ArgumentOutOfRangeException ("count", "< 0 || > this.Length");
+                       if (startIndex - count + 1 < 0)
+                               throw new ArgumentOutOfRangeException ("startIndex - count + 1 < 0");
+
+                       if (this.m_stringLength == 0)
+                               return -1;
+
+                       return LastIndexOfAnyUnchecked (anyOf, startIndex, count);
+               }
+
+               private unsafe int LastIndexOfAnyUnchecked (char [] anyOf, int startIndex, int count)
+               {
+                       if (anyOf.Length == 1)
+                               return LastIndexOfUnchecked (anyOf[0], startIndex, count);
+
+                       fixed (char* start = &m_firstChar, testStart = anyOf) {
+                               char* ptr = start + startIndex;
+                               char* ptrEnd = ptr - count;
+                               char* test;
+                               char* testEnd = testStart + anyOf.Length;
+
+                               while (ptr != ptrEnd) {
+                                       test = testStart;
+                                       while (test != testEnd) {
+                                               if (*test == *ptr)
+                                                       return (int)(ptr - start);
+                                               test++;
+                                       }
+                                       ptr--;
+                               }
+                               return -1;
+                       }
+               }
+
+        internal static int nativeCompareOrdinalEx (String strA, int indexA, String strB, int indexB, int count)
+        {
+               return CompareOrdinalUnchecked (strA, indexA, count, strB, indexB, count);
+        }
+
+               unsafe String ReplaceInternal (char oldChar, char newChar)
+               {
+#if !BOOTSTRAP_BASIC                   
+                       if (this.m_stringLength == 0 || oldChar == newChar)
+                               return this;
+#endif
+                       int start_pos = IndexOfUnchecked (oldChar, 0, this.m_stringLength);
+#if !BOOTSTRAP_BASIC
+                       if (start_pos == -1)
+                               return this;
+#endif
+                       if (start_pos < 4)
+                               start_pos = 0;
+
+                       string tmp = FastAllocateString (m_stringLength);
+                       fixed (char* dest = tmp, src = &m_firstChar) {
+                               if (start_pos != 0)
+                                       CharCopy (dest, src, start_pos);
+
+                               char* end_ptr = dest + m_stringLength;
+                               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;
+               }
+
+               public String ReplaceInternal (String oldValue, String newValue)
+               {
+                       // LAMESPEC: According to MSDN the following method is culture-sensitive but this seems to be incorrect
+                       // LAMESPEC: Result is undefined if result Length is longer than maximum string Length
+
+                       if (oldValue == null)
+                               throw new ArgumentNullException ("oldValue");
+
+                       if (oldValue.Length == 0)
+                               throw new ArgumentException ("oldValue is the empty string.");
+
+                       if (this.Length == 0)
+#if BOOTSTRAP_BASIC
+                               throw new NotImplementedException ("BOOTSTRAP_BASIC");
+#else
+                               return this;
+#endif
+                       if (newValue == null)
+                               newValue = Empty;
+
+                       return ReplaceUnchecked (oldValue, newValue);
+               }
+
+               private unsafe String ReplaceUnchecked (String oldValue, String newValue)
+               {
+                       if (oldValue.m_stringLength > m_stringLength)
+#if BOOTSTRAP_BASIC
+                               throw new NotImplementedException ("BOOTSTRAP_BASIC");
+#else
+                               return this;
+#endif
+
+                       if (oldValue.m_stringLength == 1 && newValue.m_stringLength == 1) {
+                               return Replace (oldValue[0], newValue[0]);
+                               // ENHANCE: It would be possible to special case oldValue.m_stringLength == newValue.m_stringLength
+                               // because the m_stringLength of the result would be this.m_stringLength and m_stringLength calculation unneccesary
+                       }
+
+                       const int maxValue = 200; // Allocate 800 byte maximum
+                       int* dat = stackalloc int[maxValue];
+                       fixed (char* source = &m_firstChar, replace = newValue) {
+                               int i = 0, count = 0;
+                               while (i < m_stringLength) {
+                                       int found = IndexOfUnchecked (oldValue, i, m_stringLength - i);
+                                       if (found < 0)
+                                               break;
+                                       else {
+                                               if (count < maxValue)
+                                                       dat[count++] = found;
+                                               else
+                                                       return ReplaceFallback (oldValue, newValue, maxValue);
+                                       }
+                                       i = found + oldValue.m_stringLength;
+                               }
+                               if (count == 0)
+#if BOOTSTRAP_BASIC
+                               throw new NotImplementedException ("BOOTSTRAP_BASIC");
+#else
+                               return this;
+#endif
+                               int nlen = 0;
+                               checked {
+                                       try {
+                                               nlen = this.m_stringLength + ((newValue.m_stringLength - oldValue.m_stringLength) * count);
+                                       } catch (OverflowException) {
+                                               throw new OutOfMemoryException ();
+                                       }
+                               }
+                               String tmp = FastAllocateString (nlen);
+
+                               int curPos = 0, lastReadPos = 0;
+                               fixed (char* dest = tmp) {
+                                       for (int j = 0; j < count; j++) {
+                                               int precopy = dat[j] - lastReadPos;
+                                               CharCopy (dest + curPos, source + lastReadPos, precopy);
+                                               curPos += precopy;
+                                               lastReadPos = dat[j] + oldValue.m_stringLength;
+                                               CharCopy (dest + curPos, replace, newValue.m_stringLength);
+                                               curPos += newValue.m_stringLength;
+                                       }
+                                       CharCopy (dest + curPos, source + lastReadPos, m_stringLength - lastReadPos);
+                               }
+                               return tmp;
+                       }
+               }
+
+               private String ReplaceFallback (String oldValue, String newValue, int testedCount)
+               {
+                       int lengthEstimate = this.m_stringLength + ((newValue.m_stringLength - oldValue.m_stringLength) * testedCount);
+                       StringBuilder sb = new StringBuilder (lengthEstimate);
+                       for (int i = 0; i < m_stringLength;) {
+                               int found = IndexOfUnchecked (oldValue, i, m_stringLength - i);
+                               if (found < 0) {
+                                       sb.Append (InternalSubString (i, m_stringLength - i));
+                                       break;
+                               }
+                               sb.Append (InternalSubString (i, found - i));
+                               sb.Append (newValue);
+                               i = found + oldValue.m_stringLength;
+                       }
+                       return sb.ToString ();
+
+               }
+
+               unsafe String PadHelper (int totalWidth, char paddingChar, bool isRightPadded)
+               {
+                       if (totalWidth < 0)
+                               throw new ArgumentOutOfRangeException ("totalWidth", "Non-negative number required");
+                       if (totalWidth <= m_stringLength)
+#if BOOTSTRAP_BASIC
+                               throw new NotImplementedException ("BOOTSTRAP_BASIC");
+#else                  
+                               return this;
+#endif
+                       string result = FastAllocateString (totalWidth);
+
+                       fixed (char *dest = result, src = &m_firstChar) {
+                               if (isRightPadded) {
+                                       CharCopy (dest, src, m_stringLength);
+                                       char *end = dest + totalWidth;
+                                       char *p = dest + m_stringLength;
+                                       while (p < end) {
+                                               *p++ = paddingChar;
+                                       }
+                               } else {
+                                       char *p = dest;
+                                       char *end = p + totalWidth - m_stringLength;
+                                       while (p < end) {
+                                               *p++ = paddingChar;
+                                       }
+                                       CharCopy (p, src, m_stringLength);
+                               }
+                       }
+
+                       return result;
+               }
+
+               internal bool StartsWithOrdinalUnchecked (String value)
+               {
+#if BOOTSTRAP_BASIC
+                       throw new NotImplementedException ("BOOTSTRAP_BASIC");
+#else
+                       return m_stringLength >= value.m_stringLength && CompareOrdinalUnchecked (this, 0, value.m_stringLength, value, 0, value.m_stringLength) == 0;
+#endif
+               }
+
+               internal unsafe bool IsAscii ()
+               {
+                       fixed (char* src = &m_firstChar) {
+                               char* end_ptr = src + m_stringLength;
+                               char* str_ptr = src;
+
+                               while (str_ptr != end_ptr) {
+                                       if (*str_ptr >= 0x80)
+                                               return false;
+
+                                       ++str_ptr;
+                               }
+                       }
+
+                       return true;
+               }
+
+               internal bool IsFastSort ()
+               {
+                       return false;
+               }
+
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               private extern static string InternalIsInterned (string str);
+
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               private extern static string InternalIntern (string str);
+
+               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) {
+                                       Buffer.memcpy2 ((byte*)dest, (byte*)src, count * 2);
+                                       return;
+                               }
+                       }
+                       Buffer.memcpy4 ((byte*)dest, (byte*)src, count * 2);
+               }
+
+               #region Runtime method-to-ir dependencies
+
+               /* helpers used by the runtime as well as above or eslewhere in corlib */
+               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 memcpy (byte *dest, byte *src, int size)
+               {
+                       Buffer.Memcpy (dest, src, size);
+               }
+               #endregion
+
+               // Certain constructors are redirected to CreateString methods with
+               // matching argument list. The this pointer should not be used.
+
+               private unsafe String CreateString (sbyte* value)
+               {
+                       if (value == null)
+                               return 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.");
+               }
+
+                       return CreateString (value, 0, length, null);
+               }
+
+               unsafe String CreateString (sbyte* value, int startIndex, int length)
+               {
+                       return CreateString (value, startIndex, length, null);
+               }
+
+               unsafe string CreateString (char *value)
+               {
+                       if (value == null)
+                               return Empty;
+                       char *p = value;
+                       int i = 0;
+                       while (*p != 0) {
+                               ++i;
+                               ++p;
+                       }
+                       string result = FastAllocateString (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 Empty;
+                       if (value == null)
+                               throw new ArgumentNullException ("value");
+                       if (startIndex < 0)
+                               throw new ArgumentOutOfRangeException ("startIndex");
+                       if (length < 0)
+                               throw new ArgumentOutOfRangeException ("length");
+
+                       string result = FastAllocateString (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 Empty;
+
+                       string result = FastAllocateString (length);
+
+                       fixed (char *dest = result, src = val) {
+                               CharCopy (dest, src + startIndex, length);
+                       }
+                       return result;
+               }
+
+               unsafe string CreateString (char [] val)
+               {
+                       if (val == null || val.Length == 0)
+                               return Empty;
+                       string result = FastAllocateString (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 Empty;
+                       string result = FastAllocateString (count);
+                       fixed (char *dest = result) {
+                               char *p = dest;
+                               char *end = p + count;
+                               while (p < end) {
+                                       *p = c;
+                                       p++;
+                               }
+                       }
+                       return result;
+               }
+
+               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.");
+
+                       if (enc == null) {
+                               if (value == null)
+                                       throw new ArgumentNullException ("value");
+                               if (length == 0)
+                                       return Empty;
+
+                               enc = Encoding.Default;
+                       }
+
+                       byte [] bytes = new byte [length];
+
+                       if (length != 0)
+                               fixed (byte* bytePtr = bytes)
+                                       try {
+                                               if (value == null)
+                                                       throw new ArgumentOutOfRangeException ("ptr", "Value, startIndex and length do not refer to a valid string.");
+                                               memcpy (bytePtr, (byte*) (value + startIndex), length);
+                                       } catch (NullReferenceException) {
+                                               throw new ArgumentOutOfRangeException ("ptr", "Value, startIndex and length do not refer to a valid string.");
+                                       }
+
+                       // GetString () is called even when length == 0
+                       return enc.GetString (bytes);
+               }
+       }
+}
\ No newline at end of file