3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 /*============================================================
11 ** Purpose: Your favorite String class. Native methods
12 ** are implemented in StringNative.cpp
15 ===========================================================*/
20 using System.Runtime.ConstrainedExecution;
21 using System.Globalization;
22 using System.Threading;
23 using System.Collections;
24 using System.Collections.Generic;
25 using System.Runtime.CompilerServices;
26 using System.Runtime.InteropServices;
27 using System.Runtime.Versioning;
28 using Microsoft.Win32;
29 using System.Diagnostics.Contracts;
32 // For Information on these methods, please see COMString.cpp
34 // The String class represents a static string of characters. Many of
35 // the String methods perform some type of transformation on the current
36 // instance and return the result as a new String. All comparison methods are
37 // implemented as a part of String. As with arrays, character positions
38 // (indices) are zero-based.
40 // When passing a null string into a constructor in VJ and VC, the null should be
41 // explicitly type cast to a String.
43 // String s = new String((String)null);
44 // Console.WriteLine(s);
48 public sealed partial class String : IComparable, ICloneable, IConvertible, IEnumerable
50 , IComparable<String>, IEnumerable<char>, IEquatable<String>
56 //These fields map directly onto the fields in an EE StringObject. See object.h for the layout.
58 [NonSerialized]private int m_stringLength;
60 [NonSerialized]private char m_firstChar;
62 //private static readonly char FmtMsgMarkerChar='%';
63 //private static readonly char FmtMsgFmtCodeChar='!';
64 //These are defined in Com99/src/vm/COMStringCommon.h and must be kept in [....].
65 private const int TrimHead = 0;
66 private const int TrimTail = 1;
67 private const int TrimBoth = 2;
69 // The Empty constant holds the empty string value. It is initialized by the EE during startup.
70 // It is treated as intrinsic by the JIT as so the static constructor would never run.
71 // Leaving it uninitialized would confuse debuggers.
73 //We need to call the String constructor so that the compiler doesn't mark this as a literal.
74 //Marking this as a literal would mean that it doesn't show up as a field which we can access
76 public static readonly String Empty;
79 //Native Static Methods
82 // Joins an array of strings together as one string with a separator between each original string.
84 public static String Join(String separator, params String[] value) {
86 throw new ArgumentNullException("value");
87 Contract.EndContractBlock();
88 return Join(separator, value, 0, value.Length);
92 public static String Join(String separator, params Object[] values) {
94 throw new ArgumentNullException("values");
95 Contract.EndContractBlock();
97 if (values.Length == 0 || values[0] == null)
100 if (separator == null)
101 separator = String.Empty;
103 StringBuilder result = StringBuilderCache.Acquire();
105 String value = values[0].ToString();
107 result.Append(value);
109 for (int i = 1; i < values.Length; i++) {
110 result.Append(separator);
111 if (values[i] != null) {
112 // handle the case where their ToString() override is broken
113 value = values[i].ToString();
115 result.Append(value);
118 return StringBuilderCache.GetStringAndRelease(result);
122 public static String Join<T>(String separator, IEnumerable<T> values) {
124 throw new ArgumentNullException("values");
125 Contract.Ensures(Contract.Result<String>() != null);
126 Contract.EndContractBlock();
128 if (separator == null)
129 separator = String.Empty;
131 using(IEnumerator<T> en = values.GetEnumerator()) {
135 StringBuilder result = StringBuilderCache.Acquire();
136 if (en.Current != null) {
137 // handle the case that the enumeration has null entries
138 // and the case where their ToString() override is broken
139 string value = en.Current.ToString();
141 result.Append(value);
144 while (en.MoveNext()) {
145 result.Append(separator);
146 if (en.Current != null) {
147 // handle the case that the enumeration has null entries
148 // and the case where their ToString() override is broken
149 string value = en.Current.ToString();
151 result.Append(value);
154 return StringBuilderCache.GetStringAndRelease(result);
161 public static String Join(String separator, IEnumerable<String> values) {
163 throw new ArgumentNullException("values");
164 Contract.Ensures(Contract.Result<String>() != null);
165 Contract.EndContractBlock();
167 if (separator == null)
168 separator = String.Empty;
171 using(IEnumerator<String> en = values.GetEnumerator()) {
175 StringBuilder result = StringBuilderCache.Acquire();
176 if (en.Current != null) {
177 result.Append(en.Current);
180 while (en.MoveNext()) {
181 result.Append(separator);
182 if (en.Current != null) {
183 result.Append(en.Current);
186 return StringBuilderCache.GetStringAndRelease(result);
192 private const int charPtrAlignConst = 3;
193 private const int alignConst = 7;
195 private const int charPtrAlignConst = 1;
196 private const int alignConst = 3;
199 internal char FirstChar { get { return m_firstChar; } }
201 // Joins an array of strings together as one string with a separator between each original string.
203 [System.Security.SecuritySafeCritical] // auto-generated
204 public unsafe static String Join(String separator, String[] value, int startIndex, int count) {
205 //Range check the array
207 throw new ArgumentNullException("value");
210 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
212 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
214 if (startIndex > value.Length - count)
215 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
216 Contract.EndContractBlock();
218 //Treat null as empty string.
219 if (separator == null) {
220 separator = String.Empty;
223 //If count is 0, that skews a whole bunch of the calculations below, so just special case that.
229 //Figure out the total length of the strings in value
230 int endIndex = startIndex + count - 1;
231 for (int stringToJoinIndex = startIndex; stringToJoinIndex <= endIndex; stringToJoinIndex++) {
232 if (value[stringToJoinIndex] != null) {
233 jointLength += value[stringToJoinIndex].Length;
237 //Add enough room for the separator.
238 jointLength += (count - 1) * separator.Length;
240 // Note that we may not catch all overflows with this check (since we could have wrapped around the 4gb range any number of times
241 // and landed back in the positive range.) The input array might be modifed from other threads,
242 // so we have to do an overflow check before each append below anyway. Those overflows will get caught down there.
243 if ((jointLength < 0) || ((jointLength + 1) < 0) ) {
244 throw new OutOfMemoryException();
247 //If this is an empty string, just return.
248 if (jointLength == 0) {
252 string jointString = FastAllocateString( jointLength );
253 fixed (char * pointerToJointString = &jointString.m_firstChar) {
254 UnSafeCharBuffer charBuffer = new UnSafeCharBuffer( pointerToJointString, jointLength);
256 // Append the first string first and then append each following string prefixed by the separator.
257 charBuffer.AppendString( value[startIndex] );
258 for (int stringToJoinIndex = startIndex + 1; stringToJoinIndex <= endIndex; stringToJoinIndex++) {
259 charBuffer.AppendString( separator );
260 charBuffer.AppendString( value[stringToJoinIndex] );
262 Contract.Assert(*(pointerToJointString + charBuffer.Length) == '\0', "String must be null-terminated!");
268 [System.Security.SecuritySafeCritical] // auto-generated
269 private unsafe static int CompareOrdinalIgnoreCaseHelper(String strA, String strB)
271 Contract.Requires(strA != null);
272 Contract.Requires(strB != null);
273 Contract.EndContractBlock();
274 int length = Math.Min(strA.Length, strB.Length);
276 fixed (char* ap = &strA.m_firstChar) fixed (char* bp = &strB.m_firstChar)
286 Contract.Assert((charA | charB) <= 0x7F, "strings have to be ASCII");
288 // uppercase both chars - notice that we need just one compare per char
289 if ((uint)(charA - 'a') <= (uint)('z' - 'a')) charA -= 0x20;
290 if ((uint)(charB - 'a') <= (uint)('z' - 'a')) charB -= 0x20;
292 //Return the (case-insensitive) difference between them.
294 return charA - charB;
301 return strA.Length - strB.Length;
305 // native call to COMString::CompareOrdinalEx
306 [System.Security.SecurityCritical] // auto-generated
307 [ResourceExposure(ResourceScope.None)]
308 [MethodImplAttribute(MethodImplOptions.InternalCall)]
309 internal static extern int nativeCompareOrdinalEx(String strA, int indexA, String strB, int indexB, int count);
311 //This will not work in case-insensitive mode for any character greater than 0x80.
312 //We'll throw an ArgumentException.
314 [System.Security.SecurityCritical] // auto-generated
315 [ResourceExposure(ResourceScope.None)]
316 [MethodImplAttribute(MethodImplOptions.InternalCall)]
317 unsafe internal static extern int nativeCompareOrdinalIgnoreCaseWC(String strA, sbyte *strBBytes);
320 // This is a helper method for the security team. They need to uppercase some strings (guaranteed to be less
321 // than 0x80) before security is fully initialized. Without security initialized, we can't grab resources (the nlp's)
322 // from the assembly. This provides a workaround for that problem and should NOT be used anywhere else.
324 [System.Security.SecuritySafeCritical] // auto-generated
325 internal unsafe static string SmallCharToUpper(string strIn) {
326 Contract.Requires(strIn != null);
327 Contract.EndContractBlock();
329 // Get the length and pointers to each of the buffers. Walk the length
330 // of the string and copy the characters from the inBuffer to the outBuffer,
331 // capitalizing it if necessary. We assert that all of our characters are
334 int length = strIn.Length;
335 String strOut = FastAllocateString(length);
336 fixed (char * inBuff = &strIn.m_firstChar, outBuff = &strOut.m_firstChar) {
338 for(int i = 0; i < length; i++) {
340 Contract.Assert(c <= 0x7F, "string has to be ASCII");
342 // uppercase - notice that we need just one compare
343 if ((uint)(c - 'a') <= (uint)('z' - 'a')) c -= 0x20;
345 outBuff[i] = (char)c;
348 Contract.Assert(outBuff[length]=='\0', "outBuff[length]=='\0'");
355 // NATIVE INSTANCE METHODS
360 // Search/Query methods
363 [System.Security.SecuritySafeCritical] // auto-generated
364 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
365 private unsafe static bool EqualsHelper(String strA, String strB)
367 Contract.Requires(strA != null);
368 Contract.Requires(strB != null);
369 Contract.Requires(strA.Length == strB.Length);
371 int length = strA.Length;
373 fixed (char* ap = &strA.m_firstChar) fixed (char* bp = &strB.m_firstChar)
379 // the mono jit will inline the 64-bit check and eliminate the irrelevant path
380 if (Environment.Is64BitProcess) {
381 // for AMD64 bit platform we unroll by 12 and
382 // check 3 qword at a time. This is less code
383 // than the 32 bit case and is shorter
388 if (*(long*)a != *(long*)b) return false;
389 if (*(long*)(a+4) != *(long*)(b+4)) return false;
390 if (*(long*)(a+8) != *(long*)(b+8)) return false;
391 a += 12; b += 12; length -= 12;
396 if (*(int*)a != *(int*)b) return false;
397 if (*(int*)(a+2) != *(int*)(b+2)) return false;
398 if (*(int*)(a+4) != *(int*)(b+4)) return false;
399 if (*(int*)(a+6) != *(int*)(b+6)) return false;
400 if (*(int*)(a+8) != *(int*)(b+8)) return false;
401 a += 10; b += 10; length -= 10;
405 // This depends on the fact that the String objects are
406 // always zero terminated and that the terminating zero is not included
407 // in the length. For odd string sizes, the last compare will include
408 // the zero terminator.
411 if (*(int*)a != *(int*)b) break;
412 a += 2; b += 2; length -= 2;
415 return (length <= 0);
419 [System.Security.SecuritySafeCritical] // auto-generated
420 private unsafe static int CompareOrdinalHelper(String strA, String strB)
422 Contract.Requires(strA != null);
423 Contract.Requires(strB != null);
425 int length = Math.Min(strA.Length, strB.Length);
428 fixed (char* ap = &strA.m_firstChar) fixed (char* bp = &strB.m_firstChar)
436 if (*(int*)a != *(int*)b) {
441 if (*(int*)(a+2) != *(int*)(b+2)) {
446 if (*(int*)(a+4) != *(int*)(b+4)) {
451 if (*(int*)(a+6) != *(int*)(b+6)) {
456 if (*(int*)(a+8) != *(int*)(b+8)) {
465 if( diffOffset != -1) {
466 // we already see a difference in the unrolled loop above
470 if ( (order = (int)*a - (int)*b) != 0) {
473 Contract.Assert( *(a+1) != *(b+1), "This byte must be different if we reach here!");
474 return ((int)*(a+1) - (int)*(b+1));
477 // now go back to slower code path and do comparison on 4 bytes one time.
478 // Following code also take advantage of the fact strings will
479 // use even numbers of characters (runtime will have a extra zero at the end.)
480 // so even if length is 1 here, we can still do the comparsion.
482 if (*(int*)a != *(int*)b) {
492 // found a different int on above loop
493 if ( (c = (int)*a - (int)*b) != 0) {
496 Contract.Assert( *(a+1) != *(b+1), "This byte must be different if we reach here!");
497 return ((int)*(a+1) - (int)*(b+1));
500 // At this point, we have compared all the characters in at least one string.
501 // The longer string will be larger.
502 return strA.Length - strB.Length;
506 // Determines whether two strings match.
507 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
508 public override bool Equals(Object obj) {
509 if (this == null) //this is necessary to guard against reverse-pinvokes and
510 throw new NullReferenceException(); //other callers who do not use the callvirt instruction
512 String str = obj as String;
516 if (Object.ReferenceEquals(this, obj))
519 if (this.Length != str.Length)
522 return EqualsHelper(this, str);
525 // Determines whether two strings match.
527 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
528 public bool Equals(String value) {
529 if (this == null) //this is necessary to guard against reverse-pinvokes and
530 throw new NullReferenceException(); //other callers who do not use the callvirt instruction
535 if (Object.ReferenceEquals(this, value))
538 if (this.Length != value.Length)
541 return EqualsHelper(this, value);
545 [System.Security.SecuritySafeCritical] // auto-generated
546 public bool Equals(String value, StringComparison comparisonType) {
547 if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase)
548 throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
549 Contract.EndContractBlock();
551 if ((Object)this == (Object)value) {
555 if ((Object)value == null) {
559 switch (comparisonType) {
560 case StringComparison.CurrentCulture:
561 return (CultureInfo.CurrentCulture.CompareInfo.Compare(this, value, CompareOptions.None) == 0);
563 case StringComparison.CurrentCultureIgnoreCase:
564 return (CultureInfo.CurrentCulture.CompareInfo.Compare(this, value, CompareOptions.IgnoreCase) == 0);
566 case StringComparison.InvariantCulture:
567 return (CultureInfo.InvariantCulture.CompareInfo.Compare(this, value, CompareOptions.None) == 0);
569 case StringComparison.InvariantCultureIgnoreCase:
570 return (CultureInfo.InvariantCulture.CompareInfo.Compare(this, value, CompareOptions.IgnoreCase) == 0);
572 case StringComparison.Ordinal:
573 if (this.Length != value.Length)
575 return EqualsHelper(this, value);
577 case StringComparison.OrdinalIgnoreCase:
578 if (this.Length != value.Length)
581 // If both strings are ASCII strings, we can take the fast path.
582 if (this.IsAscii() && value.IsAscii()) {
583 return (CompareOrdinalIgnoreCaseHelper(this, value) == 0);
585 // Take the slow path.
586 return (TextInfo.CompareOrdinalIgnoreCase(this, value) == 0);
589 throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
594 // Determines whether two Strings match.
596 public static bool Equals(String a, String b) {
597 if ((Object)a==(Object)b) {
601 if ((Object)a==null || (Object)b==null) {
605 if (a.Length != b.Length)
608 return EqualsHelper(a, b);
612 [System.Security.SecuritySafeCritical] // auto-generated
613 public static bool Equals(String a, String b, StringComparison comparisonType) {
614 if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase)
615 throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
616 Contract.EndContractBlock();
618 if ((Object)a==(Object)b) {
622 if ((Object)a==null || (Object)b==null) {
626 switch (comparisonType) {
627 case StringComparison.CurrentCulture:
628 return (CultureInfo.CurrentCulture.CompareInfo.Compare(a, b, CompareOptions.None) == 0);
630 case StringComparison.CurrentCultureIgnoreCase:
631 return (CultureInfo.CurrentCulture.CompareInfo.Compare(a, b, CompareOptions.IgnoreCase) == 0);
633 case StringComparison.InvariantCulture:
634 return (CultureInfo.InvariantCulture.CompareInfo.Compare(a, b, CompareOptions.None) == 0);
636 case StringComparison.InvariantCultureIgnoreCase:
637 return (CultureInfo.InvariantCulture.CompareInfo.Compare(a, b, CompareOptions.IgnoreCase) == 0);
639 case StringComparison.Ordinal:
640 if (a.Length != b.Length)
643 return EqualsHelper(a, b);
645 case StringComparison.OrdinalIgnoreCase:
646 if (a.Length != b.Length)
649 // If both strings are ASCII strings, we can take the fast path.
650 if (a.IsAscii() && b.IsAscii()) {
651 return (CompareOrdinalIgnoreCaseHelper(a, b) == 0);
653 // Take the slow path.
655 return (TextInfo.CompareOrdinalIgnoreCase(a, b) == 0);
659 throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
663 public static bool operator == (String a, String b) {
664 return String.Equals(a, b);
667 public static bool operator != (String a, String b) {
668 return !String.Equals(a, b);
671 // Gets the character at a specified position.
673 // Spec#: Apply the precondition here using a contract assembly. Potential perf issue.
674 [System.Runtime.CompilerServices.IndexerName("Chars")]
676 public unsafe char this[int index] {
678 if (index < 0 || index >= m_stringLength)
679 throw new IndexOutOfRangeException ();
680 fixed (char* c = &m_firstChar)
685 public extern char this[int index] {
686 [ResourceExposure(ResourceScope.None)]
687 [MethodImpl(MethodImplOptions.InternalCall)]
688 [System.Security.SecuritySafeCritical] // public member
692 // Converts a substring of this string to an array of characters. Copies the
693 // characters of this string beginning at position startIndex and ending at
694 // startIndex + length - 1 to the character array buffer, beginning
695 // at bufferStartIndex.
697 [System.Security.SecuritySafeCritical] // auto-generated
698 unsafe public void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count)
700 if (destination == null)
701 throw new ArgumentNullException("destination");
703 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
705 throw new ArgumentOutOfRangeException("sourceIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
706 if (count > Length - sourceIndex)
707 throw new ArgumentOutOfRangeException("sourceIndex", Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
708 if (destinationIndex > destination.Length - count || destinationIndex < 0)
709 throw new ArgumentOutOfRangeException("destinationIndex", Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
710 Contract.EndContractBlock();
712 // Note: fixed does not like empty arrays
715 fixed (char* src = &this.m_firstChar)
716 fixed (char* dest = destination)
717 wstrcpy(dest + destinationIndex, src + sourceIndex, count);
721 // Returns the entire string as an array of characters.
722 [System.Security.SecuritySafeCritical] // auto-generated
723 unsafe public char[] ToCharArray() {
726 char[] chars = new char[length];
729 fixed (char* src = &this.m_firstChar)
730 fixed (char* dest = chars) {
731 wstrcpy(dest, src, length);
737 // Returns a substring of this string as an array of characters.
739 [System.Security.SecuritySafeCritical] // auto-generated
740 unsafe public char[] ToCharArray(int startIndex, int length)
742 // Range check everything.
743 if (startIndex < 0 || startIndex > Length || startIndex > Length - length)
744 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
746 throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_Index"));
747 Contract.EndContractBlock();
749 char[] chars = new char[length];
752 fixed (char* src = &this.m_firstChar)
753 fixed (char* dest = chars) {
754 wstrcpy(dest, src + startIndex, length);
761 public static bool IsNullOrEmpty(String value) {
762 return (value == null || value.Length == 0);
766 public static bool IsNullOrWhiteSpace(String value) {
767 if (value == null) return true;
769 for(int i = 0; i < value.Length; i++) {
770 if(!Char.IsWhiteSpace(value[i])) return false;
776 #if FEATURE_RANDOMIZED_STRING_HASHING
778 // This method is called by reflection in System.Xml
779 [System.Security.SecurityCritical]
780 [ResourceExposure(ResourceScope.None)]
781 [MethodImplAttribute(MethodImplOptions.InternalCall)]
782 internal static extern int InternalMarvin32HashString(string s, int strLen, long additionalEntropy);
784 [System.Security.SecuritySafeCritical]
785 [ResourceExposure(ResourceScope.None)]
786 internal static bool UseRandomizedHashing() {
787 return InternalUseRandomizedHashing();
790 [System.Security.SecurityCritical]
791 [System.Security.SuppressUnmanagedCodeSecurity]
792 [ResourceExposure(ResourceScope.None)]
793 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
794 private static extern bool InternalUseRandomizedHashing();
797 // Gets a hash code for this string. If strings A and B are such that A.Equals(B), then
798 // they will return the same hash code.
799 [System.Security.SecuritySafeCritical] // auto-generated
800 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
801 public override int GetHashCode() {
803 #if FEATURE_RANDOMIZED_STRING_HASHING
804 if(HashHelpers.s_UseRandomizedStringHashing)
806 return InternalMarvin32HashString(this, this.Length, 0);
808 #endif // FEATURE_RANDOMIZED_STRING_HASHING
811 fixed (char *src = this) {
812 Contract.Assert(src[this.Length] == '\0', "src[this.Length] == '\\0'");
813 Contract.Assert( ((int)src)%4 == 0, "Managed string should start at 4 bytes boundary");
816 int hash1 = (5381<<16) + 5381;
824 int* pint = (int *)src;
825 int len = this.Length;
828 hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
829 hash2 = ((hash2 << 5) + hash2 + (hash2 >> 27)) ^ pint[1];
836 hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
841 while ((c = s[0]) != 0) {
842 hash1 = ((hash1 << 5) + hash1) ^ c;
846 hash2 = ((hash2 << 5) + hash2) ^ c;
851 // We want to ensure we can change our hash function daily.
852 // This is perfectly fine as long as you don't persist the
853 // value from GetHashCode to disk or count on String A
854 // hashing before string B. Those are bugs in your code.
855 hash1 ^= ThisAssembly.DailyBuildNumber;
857 return hash1 + (hash2 * 1566083941);
862 // Use this if and only if you need the hashcode to not change across app domains (e.g. you have an app domain agile
864 [System.Security.SecuritySafeCritical] // auto-generated
865 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
866 internal int GetLegacyNonRandomizedHashCode() {
868 fixed (char *src = this) {
869 Contract.Assert(src[this.Length] == '\0', "src[this.Length] == '\\0'");
870 Contract.Assert( ((int)src)%4 == 0, "Managed string should start at 4 bytes boundary");
873 int hash1 = (5381<<16) + 5381;
881 int* pint = (int *)src;
882 int len = this.Length;
885 hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
886 hash2 = ((hash2 << 5) + hash2 + (hash2 >> 27)) ^ pint[1];
893 hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
898 while ((c = s[0]) != 0) {
899 hash1 = ((hash1 << 5) + hash1) ^ c;
903 hash2 = ((hash2 << 5) + hash2) ^ c;
908 // We want to ensure we can change our hash function daily.
909 // This is perfectly fine as long as you don't persist the
910 // value from GetHashCode to disk or count on String A
911 // hashing before string B. Those are bugs in your code.
912 hash1 ^= ThisAssembly.DailyBuildNumber;
914 return hash1 + (hash2 * 1566083941);
919 // Gets the length of this string
921 /// This is a EE implemented function so that the JIT can recognise is specially
922 /// and eliminate checks on character fetchs in a loop like:
923 /// for(int I = 0; I < str.Length; i++) str[i]
924 /// The actually code generated for this will be one instruction and will be inlined.
926 // Spec#: Add postcondition in a contract assembly. Potential perf problem.
927 public extern int Length {
928 [System.Security.SecuritySafeCritical] // auto-generated
929 [ResourceExposure(ResourceScope.None)]
930 [MethodImplAttribute(MethodImplOptions.InternalCall)]
934 // Creates an array of strings by splitting this string at each
935 // occurence of a separator. The separator is searched for, and if found,
936 // the substring preceding the occurence is stored as the first element in
937 // the array of strings. We then continue in this manner by searching
938 // the substring that follows the occurence. On the other hand, if the separator
939 // is not found, the array of strings will contain this instance as its only element.
940 // If the separator is null
941 // whitespace (i.e., Character.IsWhitespace) is used as the separator.
943 public String [] Split(params char [] separator) {
944 Contract.Ensures(Contract.Result<String[]>() != null);
945 return SplitInternal(separator, Int32.MaxValue, StringSplitOptions.None);
948 // Creates an array of strings by splitting this string at each
949 // occurence of a separator. The separator is searched for, and if found,
950 // the substring preceding the occurence is stored as the first element in
951 // the array of strings. We then continue in this manner by searching
952 // the substring that follows the occurence. On the other hand, if the separator
953 // is not found, the array of strings will contain this instance as its only element.
954 // If the spearator is the empty string (i.e., String.Empty), then
955 // whitespace (i.e., Character.IsWhitespace) is used as the separator.
956 // If there are more than count different strings, the last n-(count-1)
957 // elements are concatenated and added as the last String.
959 public string[] Split(char[] separator, int count) {
960 Contract.Ensures(Contract.Result<String[]>() != null);
961 return SplitInternal(separator, count, StringSplitOptions.None);
965 public String[] Split(char[] separator, StringSplitOptions options) {
966 Contract.Ensures(Contract.Result<String[]>() != null);
967 return SplitInternal(separator, Int32.MaxValue, options);
971 public String[] Split(char[] separator, int count, StringSplitOptions options)
973 Contract.Ensures(Contract.Result<String[]>() != null);
974 return SplitInternal(separator, count, options);
978 internal String[] SplitInternal(char[] separator, int count, StringSplitOptions options)
981 throw new ArgumentOutOfRangeException("count",
982 Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
984 if (options < StringSplitOptions.None || options > StringSplitOptions.RemoveEmptyEntries)
985 throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", options));
986 Contract.Ensures(Contract.Result<String[]>() != null);
987 Contract.EndContractBlock();
989 bool omitEmptyEntries = (options == StringSplitOptions.RemoveEmptyEntries);
991 if ((count == 0) || (omitEmptyEntries && this.Length == 0))
993 return new String[0];
996 int[] sepList = new int[Length];
997 int numReplaces = MakeSeparatorList(separator, ref sepList);
999 //Handle the special case of no replaces and special count.
1000 if (0 == numReplaces || count == 1) {
1001 String[] stringArray = new String[1];
1002 stringArray[0] = this;
1006 if(omitEmptyEntries)
1008 return InternalSplitOmitEmptyEntries(sepList, null, numReplaces, count);
1012 return InternalSplitKeepEmptyEntries(sepList, null, numReplaces, count);
1017 public String [] Split(String[] separator, StringSplitOptions options) {
1018 Contract.Ensures(Contract.Result<String[]>() != null);
1019 return Split(separator, Int32.MaxValue, options);
1023 public String[] Split(String[] separator, Int32 count, StringSplitOptions options) {
1025 throw new ArgumentOutOfRangeException("count",
1026 Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
1029 if (options < StringSplitOptions.None || options > StringSplitOptions.RemoveEmptyEntries) {
1030 throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)options));
1032 Contract.EndContractBlock();
1034 bool omitEmptyEntries = (options == StringSplitOptions.RemoveEmptyEntries);
1036 if (separator == null || separator.Length ==0) {
1037 return SplitInternal((char[]) null, count, options);
1040 if ((count == 0) || (omitEmptyEntries && this.Length ==0)) {
1041 return new String[0];
1044 int[] sepList = new int[Length];
1045 int[] lengthList = new int[Length];
1046 int numReplaces = MakeSeparatorList(separator, ref sepList, ref lengthList);
1048 //Handle the special case of no replaces and special count.
1049 if (0 == numReplaces || count == 1) {
1050 String[] stringArray = new String[1];
1051 stringArray[0] = this;
1055 if (omitEmptyEntries) {
1056 return InternalSplitOmitEmptyEntries(sepList, lengthList, numReplaces, count);
1059 return InternalSplitKeepEmptyEntries(sepList, lengthList, numReplaces, count);
1063 // Note a few special case in this function:
1064 // If there is no separator in the string, a string array which only contains
1065 // the original string will be returned regardless of the count.
1068 private String[] InternalSplitKeepEmptyEntries(Int32 [] sepList, Int32 [] lengthList, Int32 numReplaces, int count) {
1069 Contract.Requires(numReplaces >= 0);
1070 Contract.Requires(count >= 2);
1071 Contract.Ensures(Contract.Result<String[]>() != null);
1077 int numActualReplaces = (numReplaces < count) ? numReplaces : count;
1079 //Allocate space for the new array.
1080 //+1 for the string from the end of the last replace to the end of the String.
1081 String[] splitStrings = new String[numActualReplaces+1];
1083 for (int i = 0; i < numActualReplaces && currIndex < Length; i++) {
1084 splitStrings[arrIndex++] = Substring(currIndex, sepList[i]-currIndex );
1085 currIndex=sepList[i] + ((lengthList == null) ? 1 : lengthList[i]);
1088 //Handle the last string at the end of the array if there is one.
1089 if (currIndex < Length && numActualReplaces >= 0) {
1090 splitStrings[arrIndex] = Substring(currIndex);
1092 else if (arrIndex==numActualReplaces) {
1093 //We had a separator character at the end of a string. Rather than just allowing
1094 //a null character, we'll replace the last element in the array with an empty string.
1095 splitStrings[arrIndex] = String.Empty;
1099 return splitStrings;
1103 // This function will not keep the Empty String
1104 private String[] InternalSplitOmitEmptyEntries(Int32[] sepList, Int32[] lengthList, Int32 numReplaces, int count) {
1105 Contract.Requires(numReplaces >= 0);
1106 Contract.Requires(count >= 2);
1107 Contract.Ensures(Contract.Result<String[]>() != null);
1109 // Allocate array to hold items. This array may not be
1110 // filled completely in this function, we will create a
1111 // new array and copy string references to that new array.
1113 int maxItems = (numReplaces < count) ? (numReplaces+1): count ;
1114 String[] splitStrings = new String[maxItems];
1119 for(int i=0; i< numReplaces && currIndex < Length; i++) {
1120 if( sepList[i]-currIndex > 0) {
1121 splitStrings[arrIndex++] = Substring(currIndex, sepList[i]-currIndex );
1123 currIndex=sepList[i] + ((lengthList == null) ? 1 : lengthList[i]);
1124 if( arrIndex == count -1 ) {
1125 // If all the remaining entries at the end are empty, skip them
1126 while( i < numReplaces - 1 && currIndex == sepList[++i]) {
1127 currIndex += ((lengthList == null) ? 1 : lengthList[i]);
1133 // we must have at least one slot left to fill in the last string.
1134 Contract.Assert(arrIndex < maxItems);
1136 //Handle the last string at the end of the array if there is one.
1137 if (currIndex< Length) {
1138 splitStrings[arrIndex++] = Substring(currIndex);
1141 String[] stringArray = splitStrings;
1142 if( arrIndex!= maxItems) {
1143 stringArray = new String[arrIndex];
1144 for( int j = 0; j < arrIndex; j++) {
1145 stringArray[j] = splitStrings[j];
1151 //--------------------------------------------------------------------
1152 // This function returns number of the places within baseString where
1153 // instances of characters in Separator occur.
1154 // Args: separator -- A string containing all of the split characters.
1155 // sepList -- an array of ints for split char indicies.
1156 //--------------------------------------------------------------------
1157 [System.Security.SecuritySafeCritical] // auto-generated
1158 private unsafe int MakeSeparatorList(char[] separator, ref int[] sepList) {
1161 if (separator == null || separator.Length ==0) {
1162 fixed (char* pwzChars = &this.m_firstChar) {
1163 //If they passed null or an empty string, look for whitespace.
1164 for (int i=0; i < Length && foundCount < sepList.Length; i++) {
1165 if (Char.IsWhiteSpace(pwzChars[i])) {
1166 sepList[foundCount++]=i;
1172 int sepListCount = sepList.Length;
1173 int sepCount = separator.Length;
1174 //If they passed in a string of chars, actually look for those chars.
1175 fixed (char* pwzChars = &this.m_firstChar, pSepChars = separator) {
1176 for (int i=0; i< Length && foundCount < sepListCount; i++) {
1177 char * pSep = pSepChars;
1178 for( int j =0; j < sepCount; j++, pSep++) {
1179 if ( pwzChars[i] == *pSep) {
1180 sepList[foundCount++]=i;
1190 //--------------------------------------------------------------------
1191 // This function returns number of the places within baseString where
1192 // instances of separator strings occur.
1193 // Args: separators -- An array containing all of the split strings.
1194 // sepList -- an array of ints for split string indicies.
1195 // lengthList -- an array of ints for split string lengths.
1196 //--------------------------------------------------------------------
1197 [System.Security.SecuritySafeCritical] // auto-generated
1198 private unsafe int MakeSeparatorList(String[] separators, ref int[] sepList, ref int[] lengthList) {
1199 Contract.Assert(separators != null && separators.Length > 0, "separators != null && separators.Length > 0");
1202 int sepListCount = sepList.Length;
1203 int sepCount = separators.Length;
1205 fixed (char* pwzChars = &this.m_firstChar) {
1206 for (int i=0; i< Length && foundCount < sepListCount; i++) {
1207 for( int j =0; j < separators.Length; j++) {
1208 String separator = separators[j];
1209 if (String.IsNullOrEmpty(separator)) {
1212 Int32 currentSepLength = separator.Length;
1213 if ( pwzChars[i] == separator[0] && currentSepLength <= Length - i) {
1214 if (currentSepLength == 1
1215 || String.CompareOrdinal(this, i, separator, 0, currentSepLength) == 0) {
1216 sepList[foundCount] = i;
1217 lengthList[foundCount] = currentSepLength;
1219 i += currentSepLength - 1;
1229 // Returns a substring of this string.
1231 public String Substring (int startIndex) {
1232 return this.Substring (startIndex, Length-startIndex);
1235 // Returns a substring of this string.
1237 [System.Security.SecuritySafeCritical] // auto-generated
1238 public String Substring(int startIndex, int length) {
1241 if (startIndex < 0) {
1242 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
1245 if (startIndex > Length) {
1246 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndexLargerThanLength"));
1250 throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
1253 if (startIndex > Length - length) {
1254 throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_IndexLength"));
1256 Contract.EndContractBlock();
1259 return String.Empty;
1262 if( startIndex == 0 && length == this.Length) {
1266 return InternalSubString(startIndex, length);
1269 [System.Security.SecurityCritical] // auto-generated
1270 unsafe string InternalSubString(int startIndex, int length) {
1271 Contract.Assert( startIndex >= 0 && startIndex <= this.Length, "StartIndex is out of range!");
1272 Contract.Assert( length >= 0 && startIndex <= this.Length - length, "length is out of range!");
1274 String result = FastAllocateString(length);
1276 fixed(char* dest = &result.m_firstChar)
1277 fixed(char* src = &this.m_firstChar) {
1278 wstrcpy(dest, src + startIndex, length);
1285 // Removes a string of characters from the ends of this string.
1287 public String Trim(params char[] trimChars) {
1288 if (null==trimChars || trimChars.Length == 0) {
1289 return TrimHelper(TrimBoth);
1291 return TrimHelper(trimChars,TrimBoth);
1294 // Removes a string of characters from the beginning of this string.
1295 public String TrimStart(params char[] trimChars) {
1296 if (null==trimChars || trimChars.Length == 0) {
1297 return TrimHelper(TrimHead);
1299 return TrimHelper(trimChars,TrimHead);
1303 // Removes a string of characters from the end of this string.
1304 public String TrimEnd(params char[] trimChars) {
1305 if (null==trimChars || trimChars.Length == 0) {
1306 return TrimHelper(TrimTail);
1308 return TrimHelper(trimChars,TrimTail);
1312 // Creates a new string with the characters copied in from ptr. If
1313 // ptr is null, a 0-length string (like String.Empty) is returned.
1315 [System.Security.SecurityCritical] // auto-generated
1316 [ResourceExposure(ResourceScope.None)]
1317 [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
1318 unsafe public extern String(char *value);
1319 [System.Security.SecurityCritical] // auto-generated
1320 [ResourceExposure(ResourceScope.None)]
1321 [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
1322 unsafe public extern String(char *value, int startIndex, int length);
1324 [System.Security.SecurityCritical] // auto-generated
1325 [ResourceExposure(ResourceScope.None)]
1326 [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
1327 unsafe public extern String(sbyte *value);
1328 [System.Security.SecurityCritical] // auto-generated
1329 [ResourceExposure(ResourceScope.None)]
1330 [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
1331 unsafe public extern String(sbyte *value, int startIndex, int length);
1333 [System.Security.SecurityCritical] // auto-generated
1334 [ResourceExposure(ResourceScope.None)]
1335 [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
1336 unsafe public extern String(sbyte *value, int startIndex, int length, Encoding enc);
1338 [System.Security.SecurityCritical] // auto-generated
1339 unsafe static private String CreateString(sbyte *value, int startIndex, int length, Encoding enc) {
1341 return new String(value, startIndex, length); // default to ANSI
1344 throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
1346 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
1347 if ((value + startIndex) < value) {
1349 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));
1352 byte [] b = new byte[length];
1355 Buffer.Memcpy(b, 0, (byte*)value, startIndex, length);
1357 catch(NullReferenceException) {
1358 // If we got a NullReferencException. It means the pointer or
1359 // the index is out of range
1360 throw new ArgumentOutOfRangeException("value",
1361 Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));
1364 return enc.GetString(b);
1367 // Helper for encodings so they can talk to our buffer directly
1368 // stringLength must be the exact size we'll expect
1369 [System.Security.SecurityCritical] // auto-generated
1370 unsafe static internal String CreateStringFromEncoding(
1371 byte* bytes, int byteLength, Encoding encoding)
1373 Contract.Requires(bytes != null);
1374 Contract.Requires(byteLength >= 0);
1376 // Get our string length
1377 int stringLength = encoding.GetCharCount(bytes, byteLength, null);
1378 Contract.Assert(stringLength >= 0, "stringLength >= 0");
1380 // They gave us an empty string if they needed one
1381 // 0 bytelength might be possible if there's something in an encoder
1382 if (stringLength == 0)
1383 return String.Empty;
1385 String s = FastAllocateString(stringLength);
1386 fixed(char* pTempChars = &s.m_firstChar)
1388 int doubleCheck = encoding.GetChars(bytes, byteLength, pTempChars, stringLength, null);
1389 Contract.Assert(stringLength == doubleCheck,
1390 "Expected encoding.GetChars to return same length as encoding.GetCharCount");
1396 [System.Security.SecuritySafeCritical] // auto-generated
1397 unsafe internal int ConvertToAnsi(byte *pbNativeBuffer, int cbNativeBuffer, bool fBestFit, bool fThrowOnUnmappableChar)
1399 Contract.Assert(cbNativeBuffer >= (Length + 1) * Marshal.SystemMaxDBCSCharSize, "Insufficient buffer length passed to ConvertToAnsi");
1401 const uint CP_ACP = 0;
1404 const uint WC_NO_BEST_FIT_CHARS = 0x00000400;
1406 uint flgs = (fBestFit ? 0 : WC_NO_BEST_FIT_CHARS);
1407 uint DefaultCharUsed = 0;
1409 fixed (char* pwzChar = &this.m_firstChar)
1411 nb = Win32Native.WideCharToMultiByte(
1419 (fThrowOnUnmappableChar ? new IntPtr(&DefaultCharUsed) : IntPtr.Zero));
1422 if (0 != DefaultCharUsed)
1424 throw new ArgumentException(Environment.GetResourceString("Interop_Marshal_Unmappable_Char"));
1427 pbNativeBuffer[nb] = 0;
1431 // Normalization Methods
1432 // These just wrap calls to Normalization class
1433 public bool IsNormalized()
1435 #if !FEATURE_NORM_IDNA_ONLY
1436 // Default to Form C
1437 return IsNormalized(NormalizationForm.FormC);
1439 // Default to Form IDNA
1440 return IsNormalized((NormalizationForm)ExtendedNormalizationForms.FormIdna);
1444 [System.Security.SecuritySafeCritical] // auto-generated
1445 public bool IsNormalized(NormalizationForm normalizationForm)
1447 #if !FEATURE_NORM_IDNA_ONLY
1448 if (this.IsFastSort())
1450 // If its FastSort && one of the 4 main forms, then its already normalized
1451 if( normalizationForm == NormalizationForm.FormC ||
1452 normalizationForm == NormalizationForm.FormKC ||
1453 normalizationForm == NormalizationForm.FormD ||
1454 normalizationForm == NormalizationForm.FormKD )
1457 #endif // !FEATURE_NORM_IDNA_ONLY
1458 return Normalization.IsNormalized(this, normalizationForm);
1461 public String Normalize()
1463 #if !FEATURE_NORM_IDNA_ONLY
1464 // Default to Form C
1465 return Normalize(NormalizationForm.FormC);
1467 // Default to Form IDNA
1468 return Normalize((NormalizationForm)ExtendedNormalizationForms.FormIdna);
1472 [System.Security.SecuritySafeCritical] // auto-generated
1473 public String Normalize(NormalizationForm normalizationForm)
1475 #if !FEATURE_NORM_IDNA_ONLY
1478 // If its FastSort && one of the 4 main forms, then its already normalized
1479 if( normalizationForm == NormalizationForm.FormC ||
1480 normalizationForm == NormalizationForm.FormKC ||
1481 normalizationForm == NormalizationForm.FormD ||
1482 normalizationForm == NormalizationForm.FormKD )
1485 #endif // !FEATURE_NORM_IDNA_ONLY
1486 return Normalization.Normalize(this, normalizationForm);
1489 [System.Security.SecurityCritical] // auto-generated
1490 [ResourceExposure(ResourceScope.None)]
1491 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1492 internal extern static String FastAllocateString(int length);
1494 [System.Security.SecuritySafeCritical] // auto-generated
1495 unsafe private static void FillStringChecked(String dest, int destPos, String src)
1497 Contract.Requires(dest != null);
1498 Contract.Requires(src != null);
1499 if (src.Length > dest.Length - destPos) {
1500 throw new IndexOutOfRangeException();
1502 Contract.EndContractBlock();
1504 fixed(char *pDest = &dest.m_firstChar)
1505 fixed (char *pSrc = &src.m_firstChar) {
1506 wstrcpy(pDest + destPos, pSrc, src.Length);
1510 // Creates a new string from the characters in a subarray. The new string will
1511 // be created from the characters in value between startIndex and
1512 // startIndex + length - 1.
1514 [System.Security.SecuritySafeCritical] // auto-generated
1515 [ResourceExposure(ResourceScope.None)]
1516 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1517 public extern String(char [] value, int startIndex, int length);
1519 // Creates a new string from the characters in a subarray. The new string will be
1520 // created from the characters in value.
1523 [System.Security.SecuritySafeCritical] // auto-generated
1524 [ResourceExposure(ResourceScope.None)]
1525 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1526 public extern String(char [] value);
1528 [System.Security.SecurityCritical] // auto-generated
1529 internal static unsafe void wstrcpy(char *dmem, char *smem, int charCount)
1531 Buffer.Memcpy((byte*)dmem, (byte*)smem, charCount * 2); // 2 used everywhere instead of sizeof(char)
1534 [System.Security.SecuritySafeCritical] // auto-generated
1535 private String CtorCharArray(char [] value)
1537 if (value != null && value.Length != 0) {
1538 String result = FastAllocateString(value.Length);
1541 fixed (char * dest = result, source = value) {
1542 wstrcpy(dest, source, value.Length);
1548 return String.Empty;
1551 [System.Security.SecuritySafeCritical] // auto-generated
1552 private String CtorCharArrayStartLength(char [] value, int startIndex, int length)
1555 throw new ArgumentNullException("value");
1558 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
1561 throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
1563 if (startIndex > value.Length - length)
1564 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
1565 Contract.EndContractBlock();
1568 String result = FastAllocateString(length);
1571 fixed (char * dest = result, source = value) {
1572 wstrcpy(dest, source + startIndex, length);
1578 return String.Empty;
1581 [System.Security.SecuritySafeCritical] // auto-generated
1582 private String CtorCharCount(char c, int count)
1585 String result = FastAllocateString(count);
1589 fixed (char *dest = result) {
1591 while (((uint)dmem & 3) != 0 && count > 0) {
1595 uint cc = (uint)((c << 16) | c);
1599 ((uint *)dmem)[0] = cc;
1600 ((uint *)dmem)[1] = cc;
1603 } while (count >= 0);
1605 if ((count & 2) != 0) {
1606 ((uint *)dmem)[0] = cc;
1609 if ((count & 1) != 0)
1616 else if (count == 0)
1617 return String.Empty;
1619 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_MustBeNonNegNum", "count"));
1622 [System.Security.SecurityCritical] // auto-generated
1623 private static unsafe int wcslen(char *ptr)
1627 // The following code is (somewhat surprisingly!) significantly faster than a naive loop,
1628 // at least on x86 and the current jit.
1630 // First make sure our pointer is aligned on a dword boundary
1631 while (((uint)end & 3) != 0 && *end != 0)
1634 // The loop condition below works because if "end[0] & end[1]" is non-zero, that means
1635 // neither operand can have been zero. If is zero, we have to look at the operands individually,
1636 // but we hope this going to fairly rare.
1638 // In general, it would be incorrect to access end[1] if we haven't made sure
1639 // end[0] is non-zero. However, we know the ptr has been aligned by the loop above
1640 // so end[0] and end[1] must be in the same page, so they're either both accessible, or both not.
1642 while ((end[0] & end[1]) != 0 || (end[0] != 0 && end[1] != 0)) {
1646 // finish up with the naive loop
1647 for ( ; *end != 0; end++)
1650 int count = (int)(end - ptr);
1655 [System.Security.SecurityCritical] // auto-generated
1656 private unsafe String CtorCharPtr(char *ptr)
1659 return String.Empty;
1662 if (ptr < (char*)64000)
1663 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeStringPtrNotAtom"));
1664 #endif // FEATURE_PAL
1666 Contract.Assert(this == null, "this == null"); // this is the string constructor, we allocate it
1669 int count = wcslen(ptr);
1671 return String.Empty;
1673 String result = FastAllocateString(count);
1674 fixed (char *dest = result)
1675 wstrcpy(dest, ptr, count);
1678 catch (NullReferenceException) {
1679 throw new ArgumentOutOfRangeException("ptr", Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));
1683 [System.Security.SecurityCritical] // auto-generated
1684 private unsafe String CtorCharPtrStartLength(char *ptr, int startIndex, int length)
1687 throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
1690 if (startIndex < 0) {
1691 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
1693 Contract.EndContractBlock();
1694 Contract.Assert(this == null, "this == null"); // this is the string constructor, we allocate it
1696 char *pFrom = ptr + startIndex;
1698 // This means that the pointer operation has had an overflow
1699 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));
1703 return String.Empty;
1705 String result = FastAllocateString(length);
1708 fixed(char *dest = result)
1709 wstrcpy(dest, pFrom, length);
1712 catch (NullReferenceException) {
1713 throw new ArgumentOutOfRangeException("ptr", Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));
1717 [System.Security.SecuritySafeCritical] // auto-generated
1718 [ResourceExposure(ResourceScope.None)]
1719 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1720 public extern String(char c, int count);
1728 // Provides a culture-correct string comparison. StrA is compared to StrB
1729 // to determine whether it is lexicographically less, equal, or greater, and then returns
1730 // either a negative integer, 0, or a positive integer; respectively.
1733 public static int Compare(String strA, String strB) {
1734 return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.None);
1738 // Provides a culture-correct string comparison. strA is compared to strB
1739 // to determine whether it is lexicographically less, equal, or greater, and then a
1740 // negative integer, 0, or a positive integer is returned; respectively.
1741 // The case-sensitive option is set by ignoreCase
1744 public static int Compare(String strA, String strB, bool ignoreCase)
1747 return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase);
1749 return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.None);
1753 // Provides a more flexible function for string comparision. See StringComparison
1754 // for meaning of different comparisonType.
1756 [System.Security.SecuritySafeCritical] // auto-generated
1757 public static int Compare(String strA, String strB, StringComparison comparisonType)
1759 // Single comparison to check if comparisonType is within [CurrentCulture .. OrdinalIgnoreCase]
1760 if ((uint) (comparisonType - StringComparison.CurrentCulture) >
1761 (uint) (StringComparison.OrdinalIgnoreCase - StringComparison.CurrentCulture)) {
1762 throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
1764 Contract.EndContractBlock();
1766 if ((Object)strA == (Object)strB) {
1770 //they can't both be null;
1779 switch (comparisonType) {
1780 case StringComparison.CurrentCulture:
1781 return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.None);
1783 case StringComparison.CurrentCultureIgnoreCase:
1784 return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase);
1786 case StringComparison.InvariantCulture:
1787 return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, strB, CompareOptions.None);
1789 case StringComparison.InvariantCultureIgnoreCase:
1790 return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase);
1792 case StringComparison.Ordinal:
1793 // Most common case: first character is different.
1794 if ((strA.m_firstChar - strB.m_firstChar) != 0)
1796 return strA.m_firstChar - strB.m_firstChar;
1799 return CompareOrdinalHelper(strA, strB);
1801 case StringComparison.OrdinalIgnoreCase:
1802 // If both strings are ASCII strings, we can take the fast path.
1803 if (strA.IsAscii() && strB.IsAscii()) {
1804 return (CompareOrdinalIgnoreCaseHelper(strA, strB));
1806 // Take the slow path.
1807 return TextInfo.CompareOrdinalIgnoreCase(strA, strB);
1810 throw new NotSupportedException(Environment.GetResourceString("NotSupported_StringComparison"));
1815 // Provides a culture-correct string comparison. strA is compared to strB
1816 // to determine whether it is lexicographically less, equal, or greater, and then a
1817 // negative integer, 0, or a positive integer is returned; respectively.
1820 public static int Compare(String strA, String strB, CultureInfo culture, CompareOptions options) {
1821 if (culture==null) {
1822 throw new ArgumentNullException("culture");
1824 Contract.EndContractBlock();
1826 return culture.CompareInfo.Compare(strA, strB, options);
1831 // Provides a culture-correct string comparison. strA is compared to strB
1832 // to determine whether it is lexicographically less, equal, or greater, and then a
1833 // negative integer, 0, or a positive integer is returned; respectively.
1834 // The case-sensitive option is set by ignoreCase, and the culture is set
1838 public static int Compare(String strA, String strB, bool ignoreCase, CultureInfo culture) {
1839 if (culture == null) {
1840 throw new ArgumentNullException("culture");
1842 Contract.EndContractBlock();
1845 return culture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase);
1847 return culture.CompareInfo.Compare(strA, strB, CompareOptions.None);
1850 // Determines whether two string regions match. The substring of strA beginning
1851 // at indexA of length count is compared with the substring of strB
1852 // beginning at indexB of the same length.
1855 public static int Compare(String strA, int indexA, String strB, int indexB, int length) {
1856 int lengthA = length;
1857 int lengthB = length;
1860 if (strA.Length - indexA < lengthA) {
1861 lengthA = (strA.Length - indexA);
1866 if (strB.Length - indexB < lengthB) {
1867 lengthB = (strB.Length - indexB);
1870 return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None);
1874 // Determines whether two string regions match. The substring of strA beginning
1875 // at indexA of length count is compared with the substring of strB
1876 // beginning at indexB of the same length. Case sensitivity is determined by the ignoreCase boolean.
1879 public static int Compare(String strA, int indexA, String strB, int indexB, int length, bool ignoreCase) {
1880 int lengthA = length;
1881 int lengthB = length;
1884 if (strA.Length - indexA < lengthA) {
1885 lengthA = (strA.Length - indexA);
1890 if (strB.Length - indexB < lengthB) {
1891 lengthB = (strB.Length - indexB);
1896 return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.IgnoreCase);
1898 return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None);
1901 // Determines whether two string regions match. The substring of strA beginning
1902 // at indexA of length length is compared with the substring of strB
1903 // beginning at indexB of the same length. Case sensitivity is determined by the ignoreCase boolean,
1904 // and the culture is set by culture.
1907 public static int Compare(String strA, int indexA, String strB, int indexB, int length, bool ignoreCase, CultureInfo culture) {
1908 if (culture == null) {
1909 throw new ArgumentNullException("culture");
1911 Contract.EndContractBlock();
1913 int lengthA = length;
1914 int lengthB = length;
1917 if (strA.Length - indexA < lengthA) {
1918 lengthA = (strA.Length - indexA);
1923 if (strB.Length - indexB < lengthB) {
1924 lengthB = (strB.Length - indexB);
1929 return culture.CompareInfo.Compare(strA,indexA,lengthA, strB, indexB, lengthB,CompareOptions.IgnoreCase);
1931 return culture.CompareInfo.Compare(strA,indexA,lengthA, strB, indexB, lengthB,CompareOptions.None);
1936 // Determines whether two string regions match. The substring of strA beginning
1937 // at indexA of length length is compared with the substring of strB
1938 // beginning at indexB of the same length.
1941 public static int Compare(String strA, int indexA, String strB, int indexB, int length, CultureInfo culture, CompareOptions options) {
1942 if (culture==null) {
1943 throw new ArgumentNullException("culture");
1945 Contract.EndContractBlock();
1947 int lengthA = length;
1948 int lengthB = length;
1951 if (strA.Length - indexA < lengthA) {
1952 lengthA = (strA.Length - indexA);
1957 if (strB.Length - indexB < lengthB) {
1958 lengthB = (strB.Length - indexB);
1962 return culture.CompareInfo.Compare(strA,indexA,lengthA, strB, indexB, lengthB, options);
1966 [System.Security.SecuritySafeCritical] // auto-generated
1967 public static int Compare(String strA, int indexA, String strB, int indexB, int length, StringComparison comparisonType) {
1968 if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase) {
1969 throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
1971 Contract.EndContractBlock();
1973 if (strA == null || strB == null) {
1974 if ((Object)strA==(Object)strB) { //they're both null;
1978 return (strA==null)? -1 : 1; //-1 if A is null, 1 if B is null.
1983 throw new ArgumentOutOfRangeException("length",
1984 Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
1988 throw new ArgumentOutOfRangeException("indexA",
1989 Environment.GetResourceString("ArgumentOutOfRange_Index"));
1993 throw new ArgumentOutOfRangeException("indexB",
1994 Environment.GetResourceString("ArgumentOutOfRange_Index"));
1997 if (strA.Length - indexA < 0) {
1998 throw new ArgumentOutOfRangeException("indexA",
1999 Environment.GetResourceString("ArgumentOutOfRange_Index"));
2002 if (strB.Length - indexB < 0) {
2003 throw new ArgumentOutOfRangeException("indexB",
2004 Environment.GetResourceString("ArgumentOutOfRange_Index"));
2007 if( ( length == 0 ) ||
2008 ((strA == strB) && (indexA == indexB)) ){
2012 int lengthA = length;
2013 int lengthB = length;
2016 if (strA.Length - indexA < lengthA) {
2017 lengthA = (strA.Length - indexA);
2022 if (strB.Length - indexB < lengthB) {
2023 lengthB = (strB.Length - indexB);
2027 switch (comparisonType) {
2028 case StringComparison.CurrentCulture:
2029 return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None);
2031 case StringComparison.CurrentCultureIgnoreCase:
2032 return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.IgnoreCase);
2034 case StringComparison.InvariantCulture:
2035 return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None);
2037 case StringComparison.InvariantCultureIgnoreCase:
2038 return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.IgnoreCase);
2040 case StringComparison.Ordinal:
2042 return nativeCompareOrdinalEx(strA, indexA, strB, indexB, length);
2044 case StringComparison.OrdinalIgnoreCase:
2045 return (TextInfo.CompareOrdinalIgnoreCaseEx(strA, indexA, strB, indexB, lengthA, lengthB));
2048 throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"));
2053 // Compares this object to another object, returning an integer that
2054 // indicates the relationship. This method returns a value less than 0 if this is less than value, 0
2055 // if this is equal to value, or a value greater than 0
2056 // if this is greater than value. Strings are considered to be
2057 // greater than all non-String objects. Note that this means sorted
2058 // arrays would contain nulls, other objects, then Strings in that order.
2061 public int CompareTo(Object value) {
2062 if (value == null) {
2066 if (!(value is String)) {
2067 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeString"));
2070 return String.Compare(this,(String)value, StringComparison.CurrentCulture);
2073 // Determines the sorting relation of StrB to the current instance.
2076 public int CompareTo(String strB) {
2081 return CultureInfo.CurrentCulture.CompareInfo.Compare(this, strB, 0);
2084 // Compares strA and strB using an ordinal (code-point) comparison.
2087 public static int CompareOrdinal(String strA, String strB) {
2088 if ((Object)strA == (Object)strB) {
2092 //they can't both be null;
2101 // Most common case, first character is different.
2102 if ((strA.m_firstChar - strB.m_firstChar) != 0)
2104 return strA.m_firstChar - strB.m_firstChar;
2108 return CompareOrdinalHelper(strA, strB);
2112 // Compares strA and strB using an ordinal (code-point) comparison.
2115 [System.Security.SecuritySafeCritical] // auto-generated
2116 public static int CompareOrdinal(String strA, int indexA, String strB, int indexB, int length) {
2117 if (strA == null || strB == null) {
2118 if ((Object)strA==(Object)strB) { //they're both null;
2122 return (strA==null)? -1 : 1; //-1 if A is null, 1 if B is null.
2125 return nativeCompareOrdinalEx(strA, indexA, strB, indexB, length);
2130 public bool Contains( string value ) {
2131 return ( IndexOf(value, StringComparison.Ordinal) >=0 );
2134 // Determines whether a specified string is a suffix of the the current instance.
2136 // The case-sensitive and culture-sensitive option is set by options,
2137 // and the default culture is used.
2140 public Boolean EndsWith(String value) {
2141 return EndsWith(value, StringComparison.CurrentCulture);
2145 [System.Security.SecuritySafeCritical] // auto-generated
2147 public Boolean EndsWith(String value, StringComparison comparisonType) {
2148 if( (Object)value == null) {
2149 throw new ArgumentNullException("value");
2152 if( comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase) {
2153 throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
2155 Contract.EndContractBlock();
2157 if( (Object)this == (Object)value) {
2161 if( value.Length == 0) {
2165 switch (comparisonType) {
2166 case StringComparison.CurrentCulture:
2167 return CultureInfo.CurrentCulture.CompareInfo.IsSuffix(this, value, CompareOptions.None);
2169 case StringComparison.CurrentCultureIgnoreCase:
2170 return CultureInfo.CurrentCulture.CompareInfo.IsSuffix(this, value, CompareOptions.IgnoreCase);
2172 case StringComparison.InvariantCulture:
2173 return CultureInfo.InvariantCulture.CompareInfo.IsSuffix(this, value, CompareOptions.None);
2175 case StringComparison.InvariantCultureIgnoreCase:
2176 return CultureInfo.InvariantCulture.CompareInfo.IsSuffix(this, value, CompareOptions.IgnoreCase);
2178 case StringComparison.Ordinal:
2179 return this.Length < value.Length ? false : (nativeCompareOrdinalEx(this, this.Length -value.Length, value, 0, value.Length) == 0);
2181 case StringComparison.OrdinalIgnoreCase:
2182 return this.Length < value.Length ? false : (TextInfo.CompareOrdinalIgnoreCaseEx(this, this.Length - value.Length, value, 0, value.Length, value.Length) == 0);
2185 throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
2190 public Boolean EndsWith(String value, Boolean ignoreCase, CultureInfo culture) {
2192 throw new ArgumentNullException("value");
2194 Contract.EndContractBlock();
2196 if((object)this == (object)value) {
2200 CultureInfo referenceCulture;
2201 if (culture == null)
2202 referenceCulture = CultureInfo.CurrentCulture;
2204 referenceCulture = culture;
2206 return referenceCulture.CompareInfo.IsSuffix(this, value, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
2210 internal bool EndsWith(char value) {
2211 int thisLen = this.Length;
2213 if (this[thisLen - 1] == value)
2220 // Returns the index of the first occurance of value in the current instance.
2221 // The search starts at startIndex and runs thorough the next count characters.
2224 public int IndexOf(char value) {
2225 return IndexOf(value, 0, this.Length);
2229 public int IndexOf(char value, int startIndex) {
2230 return IndexOf(value, startIndex, this.Length - startIndex);
2234 [System.Security.SecuritySafeCritical] // auto-generated
2235 [ResourceExposure(ResourceScope.None)]
2236 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2237 public extern int IndexOf(char value, int startIndex, int count);
2239 // Returns the index of the first occurance of any character in value in the current instance.
2240 // The search starts at startIndex and runs to endIndex-1. [startIndex,endIndex).
2243 public int IndexOfAny(char [] anyOf) {
2244 return IndexOfAny(anyOf,0, this.Length);
2248 public int IndexOfAny(char [] anyOf, int startIndex) {
2249 return IndexOfAny(anyOf, startIndex, this.Length - startIndex);
2253 [System.Security.SecuritySafeCritical] // auto-generated
2254 [ResourceExposure(ResourceScope.None)]
2255 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2256 public extern int IndexOfAny(char [] anyOf, int startIndex, int count);
2259 // Determines the position within this string of the first occurence of the specified
2260 // string, according to the specified search criteria. The search begins at
2261 // the first character of this string, it is case-sensitive and ordinal (code-point)
2262 // comparison is used.
2265 public int IndexOf(String value) {
2266 return IndexOf(value, StringComparison.CurrentCulture);
2269 // Determines the position within this string of the first occurence of the specified
2270 // string, according to the specified search criteria. The search begins at
2271 // startIndex, it is case-sensitive and ordinal (code-point) comparison is used.
2274 public int IndexOf(String value, int startIndex) {
2275 return IndexOf(value, startIndex, StringComparison.CurrentCulture);
2278 // Determines the position within this string of the first occurence of the specified
2279 // string, according to the specified search criteria. The search begins at
2280 // startIndex, ends at endIndex and ordinal (code-point) comparison is used.
2283 public int IndexOf(String value, int startIndex, int count) {
2284 if (startIndex < 0 || startIndex > this.Length) {
2285 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
2288 if (count < 0 || count > this.Length - startIndex) {
2289 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
2291 Contract.EndContractBlock();
2293 return IndexOf(value, startIndex, count, StringComparison.CurrentCulture);
2297 public int IndexOf(String value, StringComparison comparisonType) {
2298 return IndexOf(value, 0, this.Length, comparisonType);
2302 public int IndexOf(String value, int startIndex, StringComparison comparisonType) {
2303 return IndexOf(value, startIndex, this.Length - startIndex, comparisonType);
2307 [System.Security.SecuritySafeCritical]
2308 public int IndexOf(String value, int startIndex, int count, StringComparison comparisonType) {
2311 throw new ArgumentNullException("value");
2313 if (startIndex < 0 || startIndex > this.Length)
2314 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
2316 if (count < 0 || startIndex > this.Length - count)
2317 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
2318 Contract.EndContractBlock();
2320 switch (comparisonType) {
2321 case StringComparison.CurrentCulture:
2322 return CultureInfo.CurrentCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.None);
2324 case StringComparison.CurrentCultureIgnoreCase:
2325 return CultureInfo.CurrentCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
2327 case StringComparison.InvariantCulture:
2328 return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.None);
2330 case StringComparison.InvariantCultureIgnoreCase:
2331 return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
2333 case StringComparison.Ordinal:
2334 return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.Ordinal);
2336 case StringComparison.OrdinalIgnoreCase:
2337 if (value.IsAscii() && this.IsAscii())
2338 return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
2340 return TextInfo.IndexOfStringOrdinalIgnoreCase(this, value, startIndex, count);
2343 throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
2347 // Returns the index of the last occurance of value in the current instance.
2348 // The search starts at startIndex and runs to endIndex. [startIndex,endIndex].
2349 // The character at position startIndex is included in the search. startIndex is the larger
2350 // index within the string.
2353 public int LastIndexOf(char value) {
2354 return LastIndexOf(value, this.Length-1, this.Length);
2358 public int LastIndexOf(char value, int startIndex){
2359 return LastIndexOf(value,startIndex,startIndex + 1);
2363 [System.Security.SecuritySafeCritical] // auto-generated
2364 [ResourceExposure(ResourceScope.None)]
2365 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2366 public extern int LastIndexOf(char value, int startIndex, int count);
2368 // Returns the index of the last occurance of any character in value in the current instance.
2369 // The search starts at startIndex and runs to endIndex. [startIndex,endIndex].
2370 // The character at position startIndex is included in the search. startIndex is the larger
2371 // index within the string.
2374 //ForceInline ... Jit can't recognize String.get_Length to determine that this is "fluff"
2376 public int LastIndexOfAny(char [] anyOf) {
2377 return LastIndexOfAny(anyOf,this.Length-1,this.Length);
2380 //ForceInline ... Jit can't recognize String.get_Length to determine that this is "fluff"
2382 public int LastIndexOfAny(char [] anyOf, int startIndex) {
2383 return LastIndexOfAny(anyOf,startIndex,startIndex + 1);
2387 [System.Security.SecuritySafeCritical] // auto-generated
2388 [ResourceExposure(ResourceScope.None)]
2389 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2390 public extern int LastIndexOfAny(char [] anyOf, int startIndex, int count);
2393 // Returns the index of the last occurance of any character in value in the current instance.
2394 // The search starts at startIndex and runs to endIndex. [startIndex,endIndex].
2395 // The character at position startIndex is included in the search. startIndex is the larger
2396 // index within the string.
2399 public int LastIndexOf(String value) {
2400 return LastIndexOf(value, this.Length-1,this.Length, StringComparison.CurrentCulture);
2404 public int LastIndexOf(String value, int startIndex) {
2405 return LastIndexOf(value, startIndex, startIndex + 1, StringComparison.CurrentCulture);
2409 public int LastIndexOf(String value, int startIndex, int count) {
2411 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
2413 Contract.EndContractBlock();
2415 return LastIndexOf(value, startIndex, count, StringComparison.CurrentCulture);
2419 public int LastIndexOf(String value, StringComparison comparisonType) {
2420 return LastIndexOf(value, this.Length-1, this.Length, comparisonType);
2424 public int LastIndexOf(String value, int startIndex, StringComparison comparisonType) {
2425 return LastIndexOf(value, startIndex, startIndex + 1, comparisonType);
2429 [System.Security.SecuritySafeCritical]
2430 public int LastIndexOf(String value, int startIndex, int count, StringComparison comparisonType) {
2432 throw new ArgumentNullException("value");
2433 Contract.EndContractBlock();
2435 // Special case for 0 length input strings
2436 if (this.Length == 0 && (startIndex == -1 || startIndex == 0))
2437 return (value.Length == 0) ? 0 : -1;
2439 // Now after handling empty strings, make sure we're not out of range
2440 if (startIndex < 0 || startIndex > this.Length)
2441 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
2443 // Make sure that we allow startIndex == this.Length
2444 if (startIndex == this.Length)
2450 // If we are looking for nothing, just return 0
2451 if (value.Length == 0 && count >= 0 && startIndex - count + 1 >= 0)
2455 // 2nd half of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0.
2456 if (count < 0 || startIndex - count + 1 < 0)
2457 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
2460 switch (comparisonType) {
2461 case StringComparison.CurrentCulture:
2462 return CultureInfo.CurrentCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.None);
2464 case StringComparison.CurrentCultureIgnoreCase:
2465 return CultureInfo.CurrentCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
2467 case StringComparison.InvariantCulture:
2468 return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.None);
2470 case StringComparison.InvariantCultureIgnoreCase:
2471 return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
2472 case StringComparison.Ordinal:
2473 return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.Ordinal);
2475 case StringComparison.OrdinalIgnoreCase:
2476 if (value.IsAscii() && this.IsAscii())
2477 return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
2479 return TextInfo.LastIndexOfStringOrdinalIgnoreCase(this, value, startIndex, count);
2481 throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
2488 public String PadLeft(int totalWidth) {
2489 return PadHelper(totalWidth, ' ', false);
2493 public String PadLeft(int totalWidth, char paddingChar) {
2494 return PadHelper(totalWidth, paddingChar, false);
2498 public String PadRight(int totalWidth) {
2499 return PadHelper(totalWidth, ' ', true);
2503 public String PadRight(int totalWidth, char paddingChar) {
2504 return PadHelper(totalWidth, paddingChar, true);
2508 [System.Security.SecuritySafeCritical] // auto-generated
2509 [ResourceExposure(ResourceScope.None)]
2510 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2511 private extern String PadHelper(int totalWidth, char paddingChar, bool isRightPadded);
2513 // Determines whether a specified string is a prefix of the current instance
2516 public Boolean StartsWith(String value) {
2517 if ((Object)value == null) {
2518 throw new ArgumentNullException("value");
2520 Contract.EndContractBlock();
2521 return StartsWith(value, StringComparison.CurrentCulture);
2525 [System.Security.SecuritySafeCritical] // auto-generated
2527 public Boolean StartsWith(String value, StringComparison comparisonType) {
2528 if( (Object)value == null) {
2529 throw new ArgumentNullException("value");
2532 if( comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase) {
2533 throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
2535 Contract.EndContractBlock();
2537 if( (Object)this == (Object)value) {
2541 if( value.Length == 0) {
2545 switch (comparisonType) {
2546 case StringComparison.CurrentCulture:
2547 return CultureInfo.CurrentCulture.CompareInfo.IsPrefix(this, value, CompareOptions.None);
2549 case StringComparison.CurrentCultureIgnoreCase:
2550 return CultureInfo.CurrentCulture.CompareInfo.IsPrefix(this, value, CompareOptions.IgnoreCase);
2552 case StringComparison.InvariantCulture:
2553 return CultureInfo.InvariantCulture.CompareInfo.IsPrefix(this, value, CompareOptions.None);
2555 case StringComparison.InvariantCultureIgnoreCase:
2556 return CultureInfo.InvariantCulture.CompareInfo.IsPrefix(this, value, CompareOptions.IgnoreCase);
2558 case StringComparison.Ordinal:
2559 if( this.Length < value.Length) {
2562 return (nativeCompareOrdinalEx(this, 0, value, 0, value.Length) == 0);
2564 case StringComparison.OrdinalIgnoreCase:
2565 if( this.Length < value.Length) {
2569 return (TextInfo.CompareOrdinalIgnoreCaseEx(this, 0, value, 0, value.Length, value.Length) == 0);
2572 throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
2577 public Boolean StartsWith(String value, Boolean ignoreCase, CultureInfo culture) {
2579 throw new ArgumentNullException("value");
2581 Contract.EndContractBlock();
2583 if((object)this == (object)value) {
2587 CultureInfo referenceCulture;
2588 if (culture == null)
2589 referenceCulture = CultureInfo.CurrentCulture;
2591 referenceCulture = culture;
2593 return referenceCulture.CompareInfo.IsPrefix(this, value, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
2596 // Creates a copy of this string in lower case.
2598 public String ToLower() {
2599 Contract.Ensures(Contract.Result<String>() != null);
2600 Contract.EndContractBlock();
2601 return this.ToLower(CultureInfo.CurrentCulture);
2604 // Creates a copy of this string in lower case. The culture is set by culture.
2606 public String ToLower(CultureInfo culture) {
2607 if (culture==null) {
2608 throw new ArgumentNullException("culture");
2610 Contract.Ensures(Contract.Result<String>() != null);
2611 Contract.EndContractBlock();
2612 return culture.TextInfo.ToLower(this);
2615 // Creates a copy of this string in lower case based on invariant culture.
2617 public String ToLowerInvariant() {
2618 Contract.Ensures(Contract.Result<String>() != null);
2619 Contract.EndContractBlock();
2620 return this.ToLower(CultureInfo.InvariantCulture);
2623 // Creates a copy of this string in upper case.
2625 public String ToUpper() {
2626 Contract.Ensures(Contract.Result<String>() != null);
2627 Contract.EndContractBlock();
2628 return this.ToUpper(CultureInfo.CurrentCulture);
2632 // Creates a copy of this string in upper case. The culture is set by culture.
2634 public String ToUpper(CultureInfo culture) {
2635 if (culture==null) {
2636 throw new ArgumentNullException("culture");
2638 Contract.Ensures(Contract.Result<String>() != null);
2639 Contract.EndContractBlock();
2640 return culture.TextInfo.ToUpper(this);
2644 //Creates a copy of this string in upper case based on invariant culture.
2646 public String ToUpperInvariant() {
2647 Contract.Ensures(Contract.Result<String>() != null);
2648 Contract.EndContractBlock();
2649 return this.ToUpper(CultureInfo.InvariantCulture);
2653 // Returns this string.
2654 public override String ToString() {
2655 Contract.Ensures(Contract.Result<String>() != null);
2656 Contract.EndContractBlock();
2660 public String ToString(IFormatProvider provider) {
2661 Contract.Ensures(Contract.Result<String>() != null);
2662 Contract.EndContractBlock();
2666 // Method required for the ICloneable interface.
2667 // There's no point in cloning a string since they're immutable, so we simply return this.
2668 public Object Clone() {
2669 Contract.Ensures(Contract.Result<Object>() != null);
2670 Contract.EndContractBlock();
2674 private static bool IsBOMWhitespace(char c)
2676 #if FEATURE_LEGACYNETCF
2677 if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8 && c == '\xFEFF')
2679 // Dev11 450846 quirk:
2680 // NetCF treats the BOM as a whitespace character when performing trim operations.
2690 // Trims the whitespace from both ends of the string. Whitespace is defined by
2691 // Char.IsWhiteSpace.
2694 public String Trim() {
2695 Contract.Ensures(Contract.Result<String>() != null);
2696 Contract.EndContractBlock();
2698 return TrimHelper(TrimBoth);
2702 [System.Security.SecuritySafeCritical] // auto-generated
2703 private String TrimHelper(int trimType) {
2704 //end will point to the first non-trimmed character on the right
2705 //start will point to the first non-trimmed character on the Left
2706 int end = this.Length-1;
2709 //Trim specified characters.
2710 if (trimType !=TrimTail) {
2711 for (start=0; start < this.Length; start++) {
2712 if (!Char.IsWhiteSpace(this[start]) && !IsBOMWhitespace(this[start])) break;
2716 if (trimType !=TrimHead) {
2717 for (end= Length -1; end >= start; end--) {
2718 if (!Char.IsWhiteSpace(this[end]) && !IsBOMWhitespace(this[start])) break;
2722 return CreateTrimmedString(start, end);
2726 [System.Security.SecuritySafeCritical] // auto-generated
2727 private String TrimHelper(char[] trimChars, int trimType) {
2728 //end will point to the first non-trimmed character on the right
2729 //start will point to the first non-trimmed character on the Left
2730 int end = this.Length-1;
2733 //Trim specified characters.
2734 if (trimType !=TrimTail) {
2735 for (start=0; start < this.Length; start++) {
2737 char ch = this[start];
2738 for( i = 0; i < trimChars.Length; i++) {
2739 if( trimChars[i] == ch) break;
2741 if( i == trimChars.Length) { // the character is not white space
2747 if (trimType !=TrimHead) {
2748 for (end= Length -1; end >= start; end--) {
2750 char ch = this[end];
2751 for(i = 0; i < trimChars.Length; i++) {
2752 if( trimChars[i] == ch) break;
2754 if( i == trimChars.Length) { // the character is not white space
2760 return CreateTrimmedString(start, end);
2764 [System.Security.SecurityCritical] // auto-generated
2765 private String CreateTrimmedString(int start, int end) {
2766 //Create a new STRINGREF and initialize it from the range determined above.
2767 int len = end -start + 1;
2768 if (len == this.Length) {
2769 // Don't allocate a new string as the trimmed string has not changed.
2774 return String.Empty;
2776 return InternalSubString(start, len);
2779 [System.Security.SecuritySafeCritical] // auto-generated
2780 public String Insert(int startIndex, String value)
2783 throw new ArgumentNullException("value");
2784 if (startIndex < 0 || startIndex > this.Length)
2785 throw new ArgumentOutOfRangeException("startIndex");
2786 Contract.Ensures(Contract.Result<String>() != null);
2787 Contract.Ensures(Contract.Result<String>().Length == this.Length + value.Length);
2788 Contract.EndContractBlock();
2789 int oldLength = Length;
2790 int insertLength = value.Length;
2791 // In case this computation overflows, newLength will be negative and FastAllocateString throws OutOfMemoryException
2792 int newLength = oldLength + insertLength;
2794 return String.Empty;
2795 String result = FastAllocateString(newLength);
2798 fixed (char* srcThis = &m_firstChar)
2800 fixed (char* srcInsert = &value.m_firstChar)
2802 fixed (char* dst = &result.m_firstChar)
2804 wstrcpy(dst, srcThis, startIndex);
2805 wstrcpy(dst + startIndex, srcInsert, insertLength);
2806 wstrcpy(dst + startIndex + insertLength, srcThis + startIndex, oldLength - startIndex);
2814 // Replaces all instances of oldChar with newChar.
2816 [System.Security.SecuritySafeCritical] // auto-generated
2817 [ResourceExposure(ResourceScope.None)]
2818 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2819 private extern String ReplaceInternal(char oldChar, char newChar);
2821 public String Replace(char oldChar, char newChar)
2823 Contract.Ensures(Contract.Result<String>() != null);
2824 Contract.Ensures(Contract.Result<String>().Length == this.Length);
2825 Contract.EndContractBlock();
2827 return ReplaceInternal(oldChar, newChar);
2830 // This method contains the same functionality as StringBuilder Replace. The only difference is that
2831 // a new String has to be allocated since Strings are immutable
2832 [System.Security.SecuritySafeCritical] // auto-generated
2833 [ResourceExposure(ResourceScope.None)]
2834 [MethodImplAttribute(MethodImplOptions.InternalCall)]
2835 private extern String ReplaceInternal(String oldValue, String newValue);
2837 public String Replace(String oldValue, String newValue)
2839 if (oldValue == null)
2840 throw new ArgumentNullException("oldValue");
2841 // Note that if newValue is null, we treat it like String.Empty.
2842 Contract.Ensures(Contract.Result<String>() != null);
2843 Contract.EndContractBlock();
2845 string s = ReplaceInternal(oldValue, newValue);
2846 #if FEATURE_LEGACYNETCF
2847 if (CompatibilitySwitches.IsAppEarlierThanWindowsPhoneMango)
2849 // Dev11 453753 quirk
2850 // for pre-Mango this function had a bug that would cause it to
2851 // drop all characters to the right of the first embedded NULL.
2852 // this was quirked on Mango for pre-Mango apps however for apps
2853 // targeting Mango the bug was fixed.
2854 int i = s.IndexOf('\0');
2856 return s.Substring(0, i);
2867 [System.Security.SecuritySafeCritical] // auto-generated
2868 public String Remove(int startIndex, int count)
2871 throw new ArgumentOutOfRangeException("startIndex",
2872 Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
2874 throw new ArgumentOutOfRangeException("count",
2875 Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
2876 if (count > Length - startIndex)
2877 throw new ArgumentOutOfRangeException("count",
2878 Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
2879 Contract.Ensures(Contract.Result<String>() != null);
2880 Contract.Ensures(Contract.Result<String>().Length == this.Length - count);
2881 Contract.EndContractBlock();
2882 int newLength = Length - count;
2884 return String.Empty;
2885 String result = FastAllocateString(newLength);
2888 fixed (char* src = &m_firstChar)
2890 fixed (char* dst = &result.m_firstChar)
2892 wstrcpy(dst, src, startIndex);
2893 wstrcpy(dst + startIndex, src + startIndex + count, newLength - startIndex);
2900 // a remove that just takes a startindex.
2901 public string Remove( int startIndex ) {
2902 if (startIndex < 0) {
2903 throw new ArgumentOutOfRangeException("startIndex",
2904 Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
2907 if (startIndex >= Length) {
2908 throw new ArgumentOutOfRangeException("startIndex",
2909 Environment.GetResourceString("ArgumentOutOfRange_StartIndexLessThanLength"));
2912 Contract.Ensures(Contract.Result<String>() != null);
2913 Contract.EndContractBlock();
2915 return Substring(0, startIndex);
2918 public static String Format(String format, Object arg0) {
2919 Contract.Ensures(Contract.Result<String>() != null);
2920 return FormatHelper(null, format, new ParamsArray(arg0));
2923 public static String Format(String format, Object arg0, Object arg1) {
2924 Contract.Ensures(Contract.Result<String>() != null);
2925 return FormatHelper(null, format, new ParamsArray(arg0, arg1));
2928 public static String Format(String format, Object arg0, Object arg1, Object arg2) {
2929 Contract.Ensures(Contract.Result<String>() != null);
2930 return FormatHelper(null, format, new ParamsArray(arg0, arg1, arg2));
2933 public static String Format(String format, params Object[] args) {
2936 // To preserve the original exception behavior, throw an exception about format if both
2937 // args and format are null. The actual null check for format is in FormatHelper.
2938 throw new ArgumentNullException((format == null) ? "format" : "args");
2940 Contract.Ensures(Contract.Result<String>() != null);
2941 Contract.EndContractBlock();
2943 return FormatHelper(null, format, new ParamsArray(args));
2946 public static String Format(IFormatProvider provider, String format, Object arg0) {
2947 Contract.Ensures(Contract.Result<String>() != null);
2948 return FormatHelper(provider, format, new ParamsArray(arg0));
2951 public static String Format(IFormatProvider provider, String format, Object arg0, Object arg1) {
2952 Contract.Ensures(Contract.Result<String>() != null);
2953 return FormatHelper(provider, format, new ParamsArray(arg0, arg1));
2956 public static String Format(IFormatProvider provider, String format, Object arg0, Object arg1, Object arg2) {
2957 Contract.Ensures(Contract.Result<String>() != null);
2958 return FormatHelper(provider, format, new ParamsArray(arg0, arg1, arg2));
2961 public static String Format(IFormatProvider provider, String format, params Object[] args) {
2964 // To preserve the original exception behavior, throw an exception about format if both
2965 // args and format are null. The actual null check for format is in FormatHelper.
2966 throw new ArgumentNullException((format == null) ? "format" : "args");
2968 Contract.Ensures(Contract.Result<String>() != null);
2969 Contract.EndContractBlock();
2971 return FormatHelper(provider, format, new ParamsArray(args));
2974 private static String FormatHelper(IFormatProvider provider, String format, ParamsArray args) {
2976 throw new ArgumentNullException("format");
2978 return StringBuilderCache.GetStringAndRelease(
2980 .Acquire(format.Length + args.Length * 8)
2981 .AppendFormatHelper(provider, format, args));
2984 [System.Security.SecuritySafeCritical] // auto-generated
2985 unsafe public static String Copy (String str) {
2987 throw new ArgumentNullException("str");
2989 Contract.Ensures(Contract.Result<String>() != null);
2990 Contract.EndContractBlock();
2992 int length = str.Length;
2994 String result = FastAllocateString(length);
2996 fixed(char* dest = &result.m_firstChar)
2997 fixed(char* src = &str.m_firstChar) {
2998 wstrcpy(dest, src, length);
3003 public static String Concat(Object arg0) {
3004 Contract.Ensures(Contract.Result<String>() != null);
3005 Contract.EndContractBlock();
3009 return String.Empty;
3011 return arg0.ToString();
3014 public static String Concat(Object arg0, Object arg1) {
3015 Contract.Ensures(Contract.Result<String>() != null);
3016 Contract.EndContractBlock();
3020 arg0 = String.Empty;
3024 arg1 = String.Empty;
3026 return Concat(arg0.ToString(), arg1.ToString());
3029 public static String Concat(Object arg0, Object arg1, Object arg2) {
3030 Contract.Ensures(Contract.Result<String>() != null);
3031 Contract.EndContractBlock();
3035 arg0 = String.Empty;
3039 arg1 = String.Empty;
3043 arg2 = String.Empty;
3046 return Concat(arg0.ToString(), arg1.ToString(), arg2.ToString());
3049 [CLSCompliant(false)]
3050 public static String Concat(Object arg0, Object arg1, Object arg2, Object arg3, __arglist)
3052 Contract.Ensures(Contract.Result<String>() != null);
3053 Contract.EndContractBlock();
3058 ArgIterator args = new ArgIterator(__arglist);
3060 //+4 to account for the 4 hard-coded arguments at the beginning of the list.
3061 argCount = args.GetRemainingCount() + 4;
3063 objArgs = new Object[argCount];
3065 //Handle the hard-coded arguments
3071 //Walk all of the args in the variable part of the argument list.
3072 for (int i=4; i<argCount; i++) {
3073 objArgs[i] = TypedReference.ToObject(args.GetNextArg());
3076 return Concat(objArgs);
3079 public static String Concat(params Object[] args) {
3081 throw new ArgumentNullException("args");
3083 Contract.Ensures(Contract.Result<String>() != null);
3084 Contract.EndContractBlock();
3086 String[] sArgs = new String[args.Length];
3089 for (int i=0; i<args.Length; i++) {
3090 object value = args[i];
3091 sArgs[i] = ((value==null)?(String.Empty):(value.ToString()));
3092 if (sArgs[i] == null) sArgs[i] = String.Empty; // value.ToString() above could have returned null
3093 totalLength += sArgs[i].Length;
3094 // check for overflow
3095 if (totalLength < 0) {
3096 throw new OutOfMemoryException();
3099 return ConcatArray(sArgs, totalLength);
3103 public static String Concat<T>(IEnumerable<T> values) {
3105 throw new ArgumentNullException("values");
3106 Contract.Ensures(Contract.Result<String>() != null);
3107 Contract.EndContractBlock();
3109 StringBuilder result = StringBuilderCache.Acquire();
3110 using(IEnumerator<T> en = values.GetEnumerator()) {
3111 while (en.MoveNext()) {
3112 if (en.Current != null) {
3113 // handle the case that the enumeration has null entries
3114 // and the case where their ToString() override is broken
3115 string value = en.Current.ToString();
3117 result.Append(value);
3121 return StringBuilderCache.GetStringAndRelease(result);
3126 public static String Concat(IEnumerable<String> values) {
3128 throw new ArgumentNullException("values");
3129 Contract.Ensures(Contract.Result<String>() != null);
3130 Contract.EndContractBlock();
3132 StringBuilder result = StringBuilderCache.Acquire();
3133 using(IEnumerator<String> en = values.GetEnumerator()) {
3134 while (en.MoveNext()) {
3135 if (en.Current != null) {
3136 result.Append(en.Current);
3140 return StringBuilderCache.GetStringAndRelease(result);
3144 [System.Security.SecuritySafeCritical] // auto-generated
3145 public static String Concat(String str0, String str1) {
3146 Contract.Ensures(Contract.Result<String>() != null);
3147 Contract.Ensures(Contract.Result<String>().Length ==
3148 (str0 == null ? 0 : str0.Length) +
3149 (str1 == null ? 0 : str1.Length));
3150 Contract.EndContractBlock();
3152 if (IsNullOrEmpty(str0)) {
3153 if (IsNullOrEmpty(str1)) {
3154 return String.Empty;
3159 if (IsNullOrEmpty(str1)) {
3163 int str0Length = str0.Length;
3165 String result = FastAllocateString(str0Length + str1.Length);
3167 FillStringChecked(result, 0, str0);
3168 FillStringChecked(result, str0Length, str1);
3173 [System.Security.SecuritySafeCritical] // auto-generated
3174 public static String Concat(String str0, String str1, String str2) {
3175 Contract.Ensures(Contract.Result<String>() != null);
3176 Contract.Ensures(Contract.Result<String>().Length ==
3177 (str0 == null ? 0 : str0.Length) +
3178 (str1 == null ? 0 : str1.Length) +
3179 (str2 == null ? 0 : str2.Length));
3180 Contract.EndContractBlock();
3182 if (str0==null && str1==null && str2==null) {
3183 return String.Empty;
3187 str0 = String.Empty;
3191 str1 = String.Empty;
3195 str2 = String.Empty;
3198 int totalLength = str0.Length + str1.Length + str2.Length;
3200 String result = FastAllocateString(totalLength);
3201 FillStringChecked(result, 0, str0);
3202 FillStringChecked(result, str0.Length, str1);
3203 FillStringChecked(result, str0.Length + str1.Length, str2);
3208 [System.Security.SecuritySafeCritical] // auto-generated
3209 public static String Concat(String str0, String str1, String str2, String str3) {
3210 Contract.Ensures(Contract.Result<String>() != null);
3211 Contract.Ensures(Contract.Result<String>().Length ==
3212 (str0 == null ? 0 : str0.Length) +
3213 (str1 == null ? 0 : str1.Length) +
3214 (str2 == null ? 0 : str2.Length) +
3215 (str3 == null ? 0 : str3.Length));
3216 Contract.EndContractBlock();
3218 if (str0==null && str1==null && str2==null && str3==null) {
3219 return String.Empty;
3223 str0 = String.Empty;
3227 str1 = String.Empty;
3231 str2 = String.Empty;
3235 str3 = String.Empty;
3238 int totalLength = str0.Length + str1.Length + str2.Length + str3.Length;
3240 String result = FastAllocateString(totalLength);
3241 FillStringChecked(result, 0, str0);
3242 FillStringChecked(result, str0.Length, str1);
3243 FillStringChecked(result, str0.Length + str1.Length, str2);
3244 FillStringChecked(result, str0.Length + str1.Length + str2.Length, str3);
3249 [System.Security.SecuritySafeCritical] // auto-generated
3250 private static String ConcatArray(String[] values, int totalLength) {
3251 String result = FastAllocateString(totalLength);
3254 for (int i=0; i<values.Length; i++) {
3255 Contract.Assert((currPos <= totalLength - values[i].Length),
3256 "[String.ConcatArray](currPos <= totalLength - values[i].Length)");
3258 FillStringChecked(result, currPos, values[i]);
3259 currPos+=values[i].Length;
3265 public static String Concat(params String[] values) {
3267 throw new ArgumentNullException("values");
3268 Contract.Ensures(Contract.Result<String>() != null);
3269 // Spec#: Consider a postcondition saying the length of this string == the sum of each string in array
3270 Contract.EndContractBlock();
3273 // Always make a copy to prevent changing the array on another thread.
3274 String[] internalValues = new String[values.Length];
3276 for (int i=0; i<values.Length; i++) {
3277 string value = values[i];
3278 internalValues[i] = ((value==null)?(String.Empty):(value));
3279 totalLength += internalValues[i].Length;
3280 // check for overflow
3281 if (totalLength < 0) {
3282 throw new OutOfMemoryException();
3286 return ConcatArray(internalValues, totalLength);
3289 [System.Security.SecuritySafeCritical] // auto-generated
3290 public static String Intern(String str) {
3292 throw new ArgumentNullException("str");
3294 Contract.Ensures(Contract.Result<String>().Length == str.Length);
3295 Contract.Ensures(str.Equals(Contract.Result<String>()));
3296 Contract.EndContractBlock();
3299 return InternalIntern (str);
3301 return Thread.GetDomain().GetOrInternString(str);
3306 [System.Security.SecuritySafeCritical] // auto-generated
3307 public static String IsInterned(String str) {
3309 throw new ArgumentNullException("str");
3311 Contract.Ensures(Contract.Result<String>() == null || Contract.Result<String>().Length == str.Length);
3312 Contract.EndContractBlock();
3315 return InternalIsInterned (str);
3317 return Thread.GetDomain().IsStringInterned(str);
3323 // IConvertible implementation
3326 public TypeCode GetTypeCode() {
3327 return TypeCode.String;
3331 bool IConvertible.ToBoolean(IFormatProvider provider) {
3332 return Convert.ToBoolean(this, provider);
3336 char IConvertible.ToChar(IFormatProvider provider) {
3337 return Convert.ToChar(this, provider);
3341 sbyte IConvertible.ToSByte(IFormatProvider provider) {
3342 return Convert.ToSByte(this, provider);
3346 byte IConvertible.ToByte(IFormatProvider provider) {
3347 return Convert.ToByte(this, provider);
3351 short IConvertible.ToInt16(IFormatProvider provider) {
3352 return Convert.ToInt16(this, provider);
3356 ushort IConvertible.ToUInt16(IFormatProvider provider) {
3357 return Convert.ToUInt16(this, provider);
3361 int IConvertible.ToInt32(IFormatProvider provider) {
3362 return Convert.ToInt32(this, provider);
3366 uint IConvertible.ToUInt32(IFormatProvider provider) {
3367 return Convert.ToUInt32(this, provider);
3371 long IConvertible.ToInt64(IFormatProvider provider) {
3372 return Convert.ToInt64(this, provider);
3376 ulong IConvertible.ToUInt64(IFormatProvider provider) {
3377 return Convert.ToUInt64(this, provider);
3381 float IConvertible.ToSingle(IFormatProvider provider) {
3382 return Convert.ToSingle(this, provider);
3386 double IConvertible.ToDouble(IFormatProvider provider) {
3387 return Convert.ToDouble(this, provider);
3391 Decimal IConvertible.ToDecimal(IFormatProvider provider) {
3392 return Convert.ToDecimal(this, provider);
3396 DateTime IConvertible.ToDateTime(IFormatProvider provider) {
3397 return Convert.ToDateTime(this, provider);
3401 Object IConvertible.ToType(Type type, IFormatProvider provider) {
3402 return Convert.DefaultToType((IConvertible)this, type, provider);
3406 // Is this a string that can be compared quickly (that is it has only characters > 0x80
3408 [System.Security.SecurityCritical] // auto-generated
3409 [ResourceExposure(ResourceScope.None)]
3410 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3411 internal extern bool IsFastSort();
3412 // Is this a string that only contains characters < 0x80.
3413 [System.Security.SecurityCritical] // auto-generated
3414 [ResourceExposure(ResourceScope.None)]
3415 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3416 internal extern bool IsAscii();
3418 // Set extra byte for odd-sized strings that came from interop as BSTR.
3419 [System.Security.SecurityCritical]
3420 [ResourceExposure(ResourceScope.None)]
3421 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3422 internal extern void SetTrailByte(byte data);
3423 // Try to retrieve the extra byte - returns false if not present.
3424 [System.Security.SecurityCritical]
3425 [ResourceExposure(ResourceScope.None)]
3426 [MethodImplAttribute(MethodImplOptions.InternalCall)]
3427 internal extern bool TryGetTrailByte(out byte data);
3429 #if !FEATURE_CORECLR
3430 public CharEnumerator GetEnumerator() {
3431 Contract.Ensures(Contract.Result<CharEnumerator>() != null);
3432 Contract.EndContractBlock();
3433 BCLDebug.Perf(false, "Avoid using String's CharEnumerator until C# special cases foreach on String - use the indexed property on String instead.");
3434 return new CharEnumerator(this);
3436 #endif // !FEATURE_CORECLR
3438 IEnumerator<char> IEnumerable<char>.GetEnumerator() {
3439 Contract.Ensures(Contract.Result<IEnumerator<char>>() != null);
3440 Contract.EndContractBlock();
3441 BCLDebug.Perf(false, "Avoid using String's CharEnumerator until C# special cases foreach on String - use the indexed property on String instead.");
3442 return new CharEnumerator(this);
3446 IEnumerator IEnumerable.GetEnumerator() {
3447 Contract.Ensures(Contract.Result<IEnumerator>() != null);
3448 Contract.EndContractBlock();
3449 BCLDebug.Perf(false, "Avoid using String's CharEnumerator until C# special cases foreach on String - use the indexed property on String instead.");
3450 return new CharEnumerator(this);
3453 // Copies the source String (byte buffer) to the destination IntPtr memory allocated with len bytes.
3454 [System.Security.SecurityCritical] // auto-generated
3455 internal unsafe static void InternalCopy(String src, IntPtr dest,int len)
3459 fixed(char* charPtr = &src.m_firstChar) {
3460 byte* srcPtr = (byte*) charPtr;
3461 byte* dstPtr = (byte*) dest;
3462 Buffer.Memcpy(dstPtr, srcPtr, len);
3469 public enum StringSplitOptions {
3471 RemoveEmptyEntries = 1