[bcl] Update to 4.6 referencesource
[mono.git] / mcs / class / corlib / ReferenceSources / String.cs
1 //
2 // System.String.cs
3 //
4 // Authors:
5 //   Patrik Torstensson
6 //   Jeffrey Stedfast (fejj@ximian.com)
7 //   Dan Lewis (dihlewis@yahoo.co.uk)
8 //   Sebastien Pouliot  <sebastien@ximian.com>
9 //   Marek Safar (marek.safar@seznam.cz)
10 //   Andreas Nahr (Classdevelopment@A-SoftTech.com)
11 //
12 // (C) 2001 Ximian, Inc.  http://www.ximian.com
13 // Copyright (C) 2004-2005 Novell (http://www.novell.com)
14 // Copyright (c) 2012 Xamarin, Inc (http://www.xamarin.com)
15 //
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
23 // 
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 // 
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 //
35 //
36
37 using System.Runtime.CompilerServices;
38 using System.Text;
39
40 namespace System
41 {
42         partial class String
43         {
44                 public int Length {
45                         get {
46                                 return m_stringLength;
47                         }
48                 }
49
50                 internal static unsafe int CompareOrdinalUnchecked (String strA, int indexA, int lenA, String strB, int indexB, int lenB)
51                 {
52                         if (strA == null) {
53                                 return strB == null ? 0 : -1;
54                         }
55                         if (strB == null) {
56                                 return 1;
57                         }
58                         int lengthA = Math.Min (lenA, strA.m_stringLength - indexA);
59                         int lengthB = Math.Min (lenB, strB.m_stringLength - indexB);
60
61                         if (lengthA == lengthB && indexA == indexB && Object.ReferenceEquals (strA, strB))
62                                 return 0;
63
64                         fixed (char* aptr = strA, bptr = strB) {
65                                 char* ap = aptr + indexA;
66                                 char* end = ap + Math.Min (lengthA, lengthB);
67                                 char* bp = bptr + indexB;
68                                 while (ap < end) {
69                                         if (*ap != *bp)
70                                                 return *ap - *bp;
71                                         ap++;
72                                         bp++;
73                                 }
74                                 return lengthA - lengthB;
75                         }
76                 }
77
78                 public int IndexOf (char value, int startIndex, int count)
79                 {
80                         if (startIndex < 0 || startIndex > this.m_stringLength)
81                                 throw new ArgumentOutOfRangeException ("startIndex", "Cannot be negative and must be< 0");
82                         if (count < 0)
83                                 throw new ArgumentOutOfRangeException ("count", "< 0");
84                         if (startIndex > this.m_stringLength - count)
85                                 throw new ArgumentOutOfRangeException ("count", "startIndex + count > this.m_stringLength");
86
87                         if ((startIndex == 0 && this.m_stringLength == 0) || (startIndex == this.m_stringLength) || (count == 0))
88                                 return -1;
89
90                         return IndexOfUnchecked (value, startIndex, count);
91                 }
92
93                 internal unsafe int IndexOfUnchecked (char value, int startIndex, int count)
94                 {
95                         // It helps JIT compiler to optimize comparison
96                         int value_32 = (int)value;
97
98                         fixed (char* start = &m_firstChar) {
99                                 char* ptr = start + startIndex;
100                                 char* end_ptr = ptr + (count >> 3 << 3);
101
102                                 while (ptr != end_ptr) {
103                                         if (*ptr == value_32)
104                                                 return (int)(ptr - start);
105                                         if (ptr[1] == value_32)
106                                                 return (int)(ptr - start + 1);
107                                         if (ptr[2] == value_32)
108                                                 return (int)(ptr - start + 2);
109                                         if (ptr[3] == value_32)
110                                                 return (int)(ptr - start + 3);
111                                         if (ptr[4] == value_32)
112                                                 return (int)(ptr - start + 4);
113                                         if (ptr[5] == value_32)
114                                                 return (int)(ptr - start + 5);
115                                         if (ptr[6] == value_32)
116                                                 return (int)(ptr - start + 6);
117                                         if (ptr[7] == value_32)
118                                                 return (int)(ptr - start + 7);
119
120                                         ptr += 8;
121                                 }
122
123                                 end_ptr += count & 0x07;
124                                 while (ptr != end_ptr) {
125                                         if (*ptr == value_32)
126                                                 return (int)(ptr - start);
127
128                                         ptr++;
129                                 }
130                                 return -1;
131                         }
132                 }
133
134                 internal unsafe int IndexOfUnchecked (string value, int startIndex, int count)
135                 {
136                         int valueLen = value.Length;
137                         if (count < valueLen)
138                                 return -1;
139
140                         if (valueLen <= 1) {
141                                 if (valueLen == 1)
142                                         return IndexOfUnchecked (value[0], startIndex, count);
143                                 return startIndex;
144                         }
145
146                         fixed (char* thisptr = &m_firstChar, valueptr = value) {
147                                 char* ap = thisptr + startIndex;
148                                 char* thisEnd = ap + count - valueLen + 1;
149                                 while (ap != thisEnd) {
150                                         if (*ap == *valueptr) {
151                                                 for (int i = 1; i < valueLen; i++) {
152                                                         if (ap[i] != valueptr[i])
153                                                                 goto NextVal;
154                                                 }
155                                                 return (int)(ap - thisptr);
156                                         }
157                                         NextVal:
158                                         ap++;
159                                 }
160                         }
161                         return -1;
162                 }
163
164                 public int IndexOfAny (char [] anyOf, int startIndex, int count)
165                 {
166                         if (anyOf == null)
167                                 throw new ArgumentNullException ();
168                         if (startIndex < 0 || startIndex > this.m_stringLength)
169                                 throw new ArgumentOutOfRangeException ();
170                         if (count < 0 || startIndex > this.m_stringLength - count)
171                                 throw new ArgumentOutOfRangeException ("count", "Count cannot be negative, and startIndex + count must be less than m_stringLength of the string.");
172
173                         return IndexOfAnyUnchecked (anyOf, startIndex, count);
174                 }               
175
176                 unsafe int IndexOfAnyUnchecked (char[] anyOf, int startIndex, int count)
177                 {
178                         if (anyOf.Length == 0)
179                                 return -1;
180
181                         if (anyOf.Length == 1)
182                                 return IndexOfUnchecked (anyOf[0], startIndex, count);
183
184                         fixed (char* any = anyOf) {
185                                 int highest = *any;
186                                 int lowest = *any;
187
188                                 char* end_any_ptr = any + anyOf.Length;
189                                 char* any_ptr = any;
190                                 while (++any_ptr != end_any_ptr) {
191                                         if (*any_ptr > highest) {
192                                                 highest = *any_ptr;
193                                                 continue;
194                                         }
195
196                                         if (*any_ptr < lowest)
197                                                 lowest = *any_ptr;
198                                 }
199
200                                 fixed (char* start = &m_firstChar) {
201                                         char* ptr = start + startIndex;
202                                         char* end_ptr = ptr + count;
203
204                                         while (ptr != end_ptr) {
205                                                 if (*ptr > highest || *ptr < lowest) {
206                                                         ptr++;
207                                                         continue;
208                                                 }
209
210                                                 if (*ptr == *any)
211                                                         return (int)(ptr - start);
212
213                                                 any_ptr = any;
214                                                 while (++any_ptr != end_any_ptr) {
215                                                         if (*ptr == *any_ptr)
216                                                                 return (int)(ptr - start);
217                                                 }
218
219                                                 ptr++;
220                                         }
221                                 }
222                         }
223                         return -1;
224                 }
225
226                 public int LastIndexOf (char value, int startIndex, int count)
227                 {
228                         if (this.m_stringLength == 0)
229                                 return -1;
230  
231                         // >= for char (> for string)
232                         if ((startIndex < 0) || (startIndex >= this.Length))
233                                 throw new ArgumentOutOfRangeException ("startIndex", "< 0 || >= this.Length");
234                         if ((count < 0) || (count > this.Length))
235                                 throw new ArgumentOutOfRangeException ("count", "< 0 || > this.Length");
236                         if (startIndex - count + 1 < 0)
237                                 throw new ArgumentOutOfRangeException ("startIndex - count + 1 < 0");
238
239                         return LastIndexOfUnchecked (value, startIndex, count);
240                 }
241
242                 internal unsafe int LastIndexOfUnchecked (char value, int startIndex, int count)
243                 {
244                         // It helps JIT compiler to optimize comparison
245                         int value_32 = (int)value;
246
247                         fixed (char* start = &m_firstChar) {
248                                 char* ptr = start + startIndex;
249                                 char* end_ptr = ptr - (count >> 3 << 3);
250
251                                 while (ptr != end_ptr) {
252                                         if (*ptr == value_32)
253                                                 return (int)(ptr - start);
254                                         if (ptr[-1] == value_32)
255                                                 return (int)(ptr - start) - 1;
256                                         if (ptr[-2] == value_32)
257                                                 return (int)(ptr - start) - 2;
258                                         if (ptr[-3] == value_32)
259                                                 return (int)(ptr - start) - 3;
260                                         if (ptr[-4] == value_32)
261                                                 return (int)(ptr - start) - 4;
262                                         if (ptr[-5] == value_32)
263                                                 return (int)(ptr - start) - 5;
264                                         if (ptr[-6] == value_32)
265                                                 return (int)(ptr - start) - 6;
266                                         if (ptr[-7] == value_32)
267                                                 return (int)(ptr - start) - 7;
268
269                                         ptr -= 8;
270                                 }
271
272                                 end_ptr -= count & 0x07;
273                                 while (ptr != end_ptr) {
274                                         if (*ptr == value_32)
275                                                 return (int)(ptr - start);
276
277                                         ptr--;
278                                 }
279                                 return -1;
280                         }
281                 }
282
283                 public int LastIndexOfAny (char [] anyOf, int startIndex, int count)
284                 {
285                         if (anyOf == null) 
286                                 throw new ArgumentNullException ();
287                         if (this.m_stringLength == 0)
288                                 return -1;
289
290                         if ((startIndex < 0) || (startIndex >= this.Length))
291                                 throw new ArgumentOutOfRangeException ("startIndex", "< 0 || > this.Length");
292                         if ((count < 0) || (count > this.Length))
293                                 throw new ArgumentOutOfRangeException ("count", "< 0 || > this.Length");
294                         if (startIndex - count + 1 < 0)
295                                 throw new ArgumentOutOfRangeException ("startIndex - count + 1 < 0");
296
297                         if (this.m_stringLength == 0)
298                                 return -1;
299
300                         return LastIndexOfAnyUnchecked (anyOf, startIndex, count);
301                 }
302
303                 private unsafe int LastIndexOfAnyUnchecked (char [] anyOf, int startIndex, int count)
304                 {
305                         if (anyOf.Length == 1)
306                                 return LastIndexOfUnchecked (anyOf[0], startIndex, count);
307
308                         fixed (char* start = &m_firstChar, testStart = anyOf) {
309                                 char* ptr = start + startIndex;
310                                 char* ptrEnd = ptr - count;
311                                 char* test;
312                                 char* testEnd = testStart + anyOf.Length;
313
314                                 while (ptr != ptrEnd) {
315                                         test = testStart;
316                                         while (test != testEnd) {
317                                                 if (*test == *ptr)
318                                                         return (int)(ptr - start);
319                                                 test++;
320                                         }
321                                         ptr--;
322                                 }
323                                 return -1;
324                         }
325                 }
326
327                 internal static int nativeCompareOrdinalEx (String strA, int indexA, String strB, int indexB, int count)
328                 {
329                         //
330                         // .net does following checks in unmanaged land only which is quite
331                         // wrong as it's not always necessary and argument names don't match
332                         // but we are compatible
333                         //
334                         if (count < 0)
335                                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
336
337                         if (indexA < 0 || indexA > strA.Length)
338                                 throw new ArgumentOutOfRangeException("indexA", Environment.GetResourceString("ArgumentOutOfRange_Index"));
339
340                         if (indexB < 0 || indexB > strB.Length)
341                                 throw new ArgumentOutOfRangeException("indexB", Environment.GetResourceString("ArgumentOutOfRange_Index"));
342
343                         return CompareOrdinalUnchecked (strA, indexA, count, strB, indexB, count);
344         }
345
346                 unsafe String ReplaceInternal (char oldChar, char newChar)
347                 {
348 #if !BOOTSTRAP_BASIC                    
349                         if (this.m_stringLength == 0 || oldChar == newChar)
350                                 return this;
351 #endif
352                         int start_pos = IndexOfUnchecked (oldChar, 0, this.m_stringLength);
353 #if !BOOTSTRAP_BASIC
354                         if (start_pos == -1)
355                                 return this;
356 #endif
357                         if (start_pos < 4)
358                                 start_pos = 0;
359
360                         string tmp = FastAllocateString (m_stringLength);
361                         fixed (char* dest = tmp, src = &m_firstChar) {
362                                 if (start_pos != 0)
363                                         CharCopy (dest, src, start_pos);
364
365                                 char* end_ptr = dest + m_stringLength;
366                                 char* dest_ptr = dest + start_pos;
367                                 char* src_ptr = src + start_pos;
368
369                                 while (dest_ptr != end_ptr) {
370                                         if (*src_ptr == oldChar)
371                                                 *dest_ptr = newChar;
372                                         else
373                                                 *dest_ptr = *src_ptr;
374
375                                         ++src_ptr;
376                                         ++dest_ptr;
377                                 }
378                         }
379                         return tmp;
380                 }
381
382                 internal String ReplaceInternal (String oldValue, String newValue)
383                 {
384                         // LAMESPEC: According to MSDN the following method is culture-sensitive but this seems to be incorrect
385                         // LAMESPEC: Result is undefined if result Length is longer than maximum string Length
386
387                         if (oldValue == null)
388                                 throw new ArgumentNullException ("oldValue");
389
390                         if (oldValue.Length == 0)
391                                 throw new ArgumentException ("oldValue is the empty string.");
392
393                         if (this.Length == 0)
394 #if BOOTSTRAP_BASIC
395                                 throw new NotImplementedException ("BOOTSTRAP_BASIC");
396 #else
397                                 return this;
398 #endif
399                         if (newValue == null)
400                                 newValue = Empty;
401
402                         return ReplaceUnchecked (oldValue, newValue);
403                 }
404
405                 private unsafe String ReplaceUnchecked (String oldValue, String newValue)
406                 {
407                         if (oldValue.m_stringLength > m_stringLength)
408 #if BOOTSTRAP_BASIC
409                                 throw new NotImplementedException ("BOOTSTRAP_BASIC");
410 #else
411                                 return this;
412 #endif
413
414                         if (oldValue.m_stringLength == 1 && newValue.m_stringLength == 1) {
415                                 return Replace (oldValue[0], newValue[0]);
416                                 // ENHANCE: It would be possible to special case oldValue.m_stringLength == newValue.m_stringLength
417                                 // because the m_stringLength of the result would be this.m_stringLength and m_stringLength calculation unneccesary
418                         }
419
420                         const int maxValue = 200; // Allocate 800 byte maximum
421                         int* dat = stackalloc int[maxValue];
422                         fixed (char* source = &m_firstChar, replace = newValue) {
423                                 int i = 0, count = 0;
424                                 while (i < m_stringLength) {
425                                         int found = IndexOfUnchecked (oldValue, i, m_stringLength - i);
426                                         if (found < 0)
427                                                 break;
428                                         else {
429                                                 if (count < maxValue)
430                                                         dat[count++] = found;
431                                                 else
432                                                         return ReplaceFallback (oldValue, newValue, maxValue);
433                                         }
434                                         i = found + oldValue.m_stringLength;
435                                 }
436                                 if (count == 0)
437 #if BOOTSTRAP_BASIC
438                                 throw new NotImplementedException ("BOOTSTRAP_BASIC");
439 #else
440                                 return this;
441 #endif
442                                 int nlen = 0;
443                                 checked {
444                                         try {
445                                                 nlen = this.m_stringLength + ((newValue.m_stringLength - oldValue.m_stringLength) * count);
446                                         } catch (OverflowException) {
447                                                 throw new OutOfMemoryException ();
448                                         }
449                                 }
450                                 String tmp = FastAllocateString (nlen);
451
452                                 int curPos = 0, lastReadPos = 0;
453                                 fixed (char* dest = tmp) {
454                                         for (int j = 0; j < count; j++) {
455                                                 int precopy = dat[j] - lastReadPos;
456                                                 CharCopy (dest + curPos, source + lastReadPos, precopy);
457                                                 curPos += precopy;
458                                                 lastReadPos = dat[j] + oldValue.m_stringLength;
459                                                 CharCopy (dest + curPos, replace, newValue.m_stringLength);
460                                                 curPos += newValue.m_stringLength;
461                                         }
462                                         CharCopy (dest + curPos, source + lastReadPos, m_stringLength - lastReadPos);
463                                 }
464                                 return tmp;
465                         }
466                 }
467
468                 private String ReplaceFallback (String oldValue, String newValue, int testedCount)
469                 {
470                         int lengthEstimate = this.m_stringLength + ((newValue.m_stringLength - oldValue.m_stringLength) * testedCount);
471                         StringBuilder sb = new StringBuilder (lengthEstimate);
472                         for (int i = 0; i < m_stringLength;) {
473                                 int found = IndexOfUnchecked (oldValue, i, m_stringLength - i);
474                                 if (found < 0) {
475                                         sb.Append (InternalSubString (i, m_stringLength - i));
476                                         break;
477                                 }
478                                 sb.Append (InternalSubString (i, found - i));
479                                 sb.Append (newValue);
480                                 i = found + oldValue.m_stringLength;
481                         }
482                         return sb.ToString ();
483
484                 }
485
486                 unsafe String PadHelper (int totalWidth, char paddingChar, bool isRightPadded)
487                 {
488                         if (totalWidth < 0)
489                                 throw new ArgumentOutOfRangeException ("totalWidth", "Non-negative number required");
490                         if (totalWidth <= m_stringLength)
491 #if BOOTSTRAP_BASIC
492                                 throw new NotImplementedException ("BOOTSTRAP_BASIC");
493 #else                   
494                                 return this;
495 #endif
496                         string result = FastAllocateString (totalWidth);
497
498                         fixed (char *dest = result, src = &m_firstChar) {
499                                 if (isRightPadded) {
500                                         CharCopy (dest, src, m_stringLength);
501                                         char *end = dest + totalWidth;
502                                         char *p = dest + m_stringLength;
503                                         while (p < end) {
504                                                 *p++ = paddingChar;
505                                         }
506                                 } else {
507                                         char *p = dest;
508                                         char *end = p + totalWidth - m_stringLength;
509                                         while (p < end) {
510                                                 *p++ = paddingChar;
511                                         }
512                                         CharCopy (p, src, m_stringLength);
513                                 }
514                         }
515
516                         return result;
517                 }
518
519                 internal bool StartsWithOrdinalUnchecked (String value)
520                 {
521 #if BOOTSTRAP_BASIC
522                         throw new NotImplementedException ("BOOTSTRAP_BASIC");
523 #else
524                         return m_stringLength >= value.m_stringLength && CompareOrdinalUnchecked (this, 0, value.m_stringLength, value, 0, value.m_stringLength) == 0;
525 #endif
526                 }
527
528                 internal unsafe bool IsAscii ()
529                 {
530                         fixed (char* src = &m_firstChar) {
531                                 char* end_ptr = src + m_stringLength;
532                                 char* str_ptr = src;
533
534                                 while (str_ptr != end_ptr) {
535                                         if (*str_ptr >= 0x80)
536                                                 return false;
537
538                                         ++str_ptr;
539                                 }
540                         }
541
542                         return true;
543                 }
544
545                 internal bool IsFastSort ()
546                 {
547                         return false;
548                 }
549
550                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
551                 private extern static string InternalIsInterned (string str);
552
553                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
554                 private extern static string InternalIntern (string str);
555
556                 internal static unsafe void CharCopy (char *dest, char *src, int count) {
557                         // Same rules as for memcpy, but with the premise that 
558                         // chars can only be aligned to even addresses if their
559                         // enclosing types are correctly aligned
560                         if ((((int)(byte*)dest | (int)(byte*)src) & 3) != 0) {
561                                 if (((int)(byte*)dest & 2) != 0 && ((int)(byte*)src & 2) != 0 && count > 0) {
562                                         ((short*)dest) [0] = ((short*)src) [0];
563                                         dest++;
564                                         src++;
565                                         count--;
566                                 }
567                                 if ((((int)(byte*)dest | (int)(byte*)src) & 2) != 0) {
568                                         Buffer.memcpy2 ((byte*)dest, (byte*)src, count * 2);
569                                         return;
570                                 }
571                         }
572                         Buffer.memcpy4 ((byte*)dest, (byte*)src, count * 2);
573                 }
574
575                 #region Runtime method-to-ir dependencies
576
577                 /* helpers used by the runtime as well as above or eslewhere in corlib */
578                 static unsafe void memset (byte *dest, int val, int len)
579                 {
580                         if (len < 8) {
581                                 while (len != 0) {
582                                         *dest = (byte)val;
583                                         ++dest;
584                                         --len;
585                                 }
586                                 return;
587                         }
588                         if (val != 0) {
589                                 val = val | (val << 8);
590                                 val = val | (val << 16);
591                         }
592                         // align to 4
593                         int rest = (int)dest & 3;
594                         if (rest != 0) {
595                                 rest = 4 - rest;
596                                 len -= rest;
597                                 do {
598                                         *dest = (byte)val;
599                                         ++dest;
600                                         --rest;
601                                 } while (rest != 0);
602                         }
603                         while (len >= 16) {
604                                 ((int*)dest) [0] = val;
605                                 ((int*)dest) [1] = val;
606                                 ((int*)dest) [2] = val;
607                                 ((int*)dest) [3] = val;
608                                 dest += 16;
609                                 len -= 16;
610                         }
611                         while (len >= 4) {
612                                 ((int*)dest) [0] = val;
613                                 dest += 4;
614                                 len -= 4;
615                         }
616                         // tail bytes
617                         while (len > 0) {
618                                 *dest = (byte)val;
619                                 dest++;
620                                 len--;
621                         }
622                 }
623
624                 static unsafe void memcpy (byte *dest, byte *src, int size)
625                 {
626                         Buffer.Memcpy (dest, src, size);
627                 }
628
629                 /* Used by the runtime */
630                 internal static unsafe void bzero (byte *dest, int len) {
631                         memset (dest, 0, len);
632                 }
633
634                 internal static unsafe void bzero_aligned_1 (byte *dest, int len) {
635                         ((byte*)dest) [0] = 0;
636                 }
637
638                 internal static unsafe void bzero_aligned_2 (byte *dest, int len) {
639                         ((short*)dest) [0] = 0;
640                 }
641
642                 internal static unsafe void bzero_aligned_4 (byte *dest, int len) {
643                         ((int*)dest) [0] = 0;
644                 }
645
646                 internal static unsafe void bzero_aligned_8 (byte *dest, int len) {
647                         ((long*)dest) [0] = 0;
648                 }
649
650                 internal static unsafe void memcpy_aligned_1 (byte *dest, byte *src, int size) {
651                         ((byte*)dest) [0] = ((byte*)src) [0];
652                 }
653
654                 internal static unsafe void memcpy_aligned_2 (byte *dest, byte *src, int size) {
655                         ((short*)dest) [0] = ((short*)src) [0];
656                 }
657
658                 internal static unsafe void memcpy_aligned_4 (byte *dest, byte *src, int size) {
659                         ((int*)dest) [0] = ((int*)src) [0];
660                 }
661
662                 internal static unsafe void memcpy_aligned_8 (byte *dest, byte *src, int size) {
663                         ((long*)dest) [0] = ((long*)src) [0];
664                 }
665
666                 #endregion
667
668                 // Certain constructors are redirected to CreateString methods with
669                 // matching argument list. The this pointer should not be used.
670
671                 private unsafe String CreateString (sbyte* value)
672                 {
673                         if (value == null)
674                                 return Empty;
675
676                         byte* bytes = (byte*) value;
677                         int length = 0;
678
679                         try {
680                                 while (bytes++ [0] != 0)
681                                         length++;
682                         } catch (NullReferenceException) {
683                                 throw new ArgumentOutOfRangeException ("ptr", "Value does not refer to a valid string.");
684                 }
685
686                         return CreateString (value, 0, length, null);
687                 }
688
689                 unsafe String CreateString (sbyte* value, int startIndex, int length)
690                 {
691                         return CreateString (value, startIndex, length, null);
692                 }
693
694                 unsafe string CreateString (char *value)
695                 {
696                         return CtorCharPtr (value);
697                 }
698
699                 unsafe string CreateString (char *value, int startIndex, int length)
700                 {
701                         return CtorCharPtrStartLength (value, startIndex, length);
702                 }
703
704                 string CreateString (char [] val, int startIndex, int length)
705                 {
706                         return CtorCharArrayStartLength (val, startIndex, length);
707                 }
708
709                 string CreateString (char [] val)
710                 {
711                         return CtorCharArray (val);
712                 }
713
714                 unsafe string CreateString (char c, int count)
715                 {
716                         if (count < 0)
717                                 throw new ArgumentOutOfRangeException ("count");
718                         if (count == 0)
719                                 return Empty;
720                         string result = FastAllocateString (count);
721                         fixed (char *dest = result) {
722                                 char *p = dest;
723                                 char *end = p + count;
724                                 while (p < end) {
725                                         *p = c;
726                                         p++;
727                                 }
728                         }
729                         return result;
730                 }
731
732                 private unsafe String CreateString (sbyte* value, int startIndex, int length, Encoding enc)
733                 {
734                         if (length < 0)
735                                 throw new ArgumentOutOfRangeException ("length", "Non-negative number required.");
736                         if (startIndex < 0)
737                                 throw new ArgumentOutOfRangeException ("startIndex", "Non-negative number required.");
738                         if (value + startIndex < value)
739                                 throw new ArgumentOutOfRangeException ("startIndex", "Value, startIndex and length do not refer to a valid string.");
740
741                         if (enc == null) {
742                                 if (value == null)
743                                         throw new ArgumentNullException ("value");
744                                 if (length == 0)
745                                         return Empty;
746
747                                 enc = Encoding.Default;
748                         }
749
750                         byte [] bytes = new byte [length];
751
752                         if (length != 0)
753                                 fixed (byte* bytePtr = bytes)
754                                         try {
755                                                 if (value == null)
756                                                         throw new ArgumentOutOfRangeException ("ptr", "Value, startIndex and length do not refer to a valid string.");
757                                                 memcpy (bytePtr, (byte*) (value + startIndex), length);
758                                         } catch (NullReferenceException) {
759                                                 throw new ArgumentOutOfRangeException ("ptr", "Value, startIndex and length do not refer to a valid string.");
760                                         }
761
762                         // GetString () is called even when length == 0
763                         return enc.GetString (bytes);
764                 }
765         }
766 }