Port String.Replace(char, char) from CoreRT
authorBruce Bowyer-Smyth <bbowyersmyth@live.com.au>
Wed, 2 Mar 2016 03:49:41 +0000 (13:49 +1000)
committerBruce Bowyer-Smyth <bbowyersmyth@live.com.au>
Wed, 2 Mar 2016 03:49:41 +0000 (13:49 +1000)
Commit migrated from https://github.com/dotnet/coreclr/commit/f007485a78024b1953a7fe1ffa845be28e93ab6c

src/coreclr/src/classlibnative/bcltype/stringnative.cpp
src/coreclr/src/classlibnative/bcltype/stringnative.h
src/coreclr/src/mscorlib/src/System/String.cs
src/coreclr/src/vm/ecalllist.h

index 554e0b9..b769ffe 100644 (file)
@@ -662,84 +662,6 @@ lExit: ;
 }
 FCIMPLEND
 
-/*===================================Replace====================================
-**Action: Replaces all instances of oldChar with newChar.
-**Returns: A new String with all instances of oldChar replaced with newChar
-**Arguments: oldChar -- the character to replace
-**           newChar -- the character with which to replace oldChar.
-**Exceptions: None
-==============================================================================*/
-FCIMPL3(LPVOID, COMString::Replace, StringObject* thisRefUNSAFE, CLR_CHAR oldChar, CLR_CHAR newChar)
-{
-    FCALL_CONTRACT;
-
-    int length = 0;
-    int firstFoundIndex = -1;
-    WCHAR *oldBuffer = NULL;
-    WCHAR *newBuffer;
-
-    STRINGREF   newString   = NULL;
-    STRINGREF   thisRef     = (STRINGREF)thisRefUNSAFE;
-
-    if (thisRef==NULL) {
-        FCThrowRes(kNullReferenceException, W("NullReference_This"));
-    }
-
-    //Perf: If no replacements required, return initial reference
-    
-    // Do it if the chars are the same...
-    
-    if ((WCHAR)oldChar == (WCHAR)newChar)
-    {
-        return thisRefUNSAFE;
-    }
-    
-    // Or if the old char isn't found.
-    oldBuffer = thisRef->GetBuffer();
-    length = thisRef->GetStringLength();
-
-    for(int i=0; i<length; i++) 
-    {
-        if ((WCHAR)oldChar==oldBuffer[i])
-        {
-            firstFoundIndex = i;
-            break;
-        }
-    }
-
-    if (-1==firstFoundIndex)
-    {  
-        return thisRefUNSAFE;
-    }
-
-
-    HELPER_METHOD_FRAME_BEGIN_RET_2(newString, thisRef);
-
-    //Get the length and allocate a new String
-    //We will definitely do an allocation here, but there's nothing which
-    //requires GC_PROTECT.
-    newString = StringObject::NewString(length);
-
-    //After allocation, thisRef may have moved
-    oldBuffer = thisRef->GetBuffer();
-
-    //Get the buffers in both of the Strings.
-    newBuffer = newString->GetBuffer();
-
-    //Copy the characters, doing the replacement as we go.
-    for (int i=0; i<firstFoundIndex; i++) {
-        newBuffer[i]=oldBuffer[i];
-    }
-    for (int i=firstFoundIndex; i<length; i++) {
-        newBuffer[i]=(oldBuffer[i]==((WCHAR)oldChar))?((WCHAR)newChar):oldBuffer[i];
-    }
-
-    HELPER_METHOD_FRAME_END();
-
-    return OBJECTREFToObject(newString);
-}
-FCIMPLEND
-
 // HELPER METHODS
 // 
 // 
index 7efe7de..c7e38da 100644 (file)
@@ -77,7 +77,6 @@ public:
     //
     static FCDECL4(Object*, PadHelper, StringObject* thisRefUNSAFE, INT32 totalWidth, CLR_CHAR paddingChar, CLR_BOOL isRightPadded);
 
-    static FCDECL3(LPVOID, Replace, StringObject* thisRef, CLR_CHAR oldChar, CLR_CHAR newChar);
     static FCDECL3(Object*, ReplaceString, StringObject* thisRef, StringObject* oldValue, StringObject* newValue);
 
     static FCDECL3(Object*, Insert, StringObject* thisRefUNSAFE, INT32 startIndex, StringObject* valueUNSAFE);
index 0877954..727679d 100644 (file)
@@ -2884,16 +2884,72 @@ namespace System {
         // Replaces all instances of oldChar with newChar.
         //
         [System.Security.SecuritySafeCritical]  // auto-generated
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        private extern String ReplaceInternal(char oldChar, char newChar);
-
         public String Replace(char oldChar, char newChar)
         {
             Contract.Ensures(Contract.Result<String>() != null);
             Contract.Ensures(Contract.Result<String>().Length == this.Length);
             Contract.EndContractBlock();
 
-            return ReplaceInternal(oldChar, newChar);
+            if (oldChar == newChar)
+                return this;
+
+            unsafe
+            {
+                int remainingLength = Length;
+
+                fixed (char* pChars = &m_firstChar)
+                {
+                    char* pSrc = pChars;
+
+                    while (remainingLength > 0)
+                    {
+                        if (*pSrc == oldChar)
+                        {
+                            break;
+                        }
+
+                        remainingLength--;
+                        pSrc++;
+                    }
+                }
+
+                if (remainingLength == 0)
+                    return this;
+
+                String result = FastAllocateString(Length);
+
+                fixed (char* pChars = &m_firstChar)
+                {
+                    fixed (char* pResult = &result.m_firstChar)
+                    {
+                        int copyLength = Length - remainingLength;
+
+                        //Copy the characters already proven not to match.
+                        if (copyLength > 0)
+                        {
+                            wstrcpy(pResult, pChars, copyLength);
+                        }
+
+                        //Copy the remaining characters, doing the replacement as we go.
+                        char* pSrc = pChars + copyLength;
+                        char* pDst = pResult + copyLength;
+
+                        do
+                        {
+                            char currentChar = *pSrc;
+                            if (currentChar == oldChar)
+                                currentChar = newChar;
+                            *pDst = currentChar;
+
+                            remainingLength--;
+                            pSrc++;
+                            pDst++;
+                        } while (remainingLength > 0);
+                    }
+                }
+
+                return result;
+            }
         }
 
         // This method contains the same functionality as StringBuilder Replace. The only difference is that
index e38a026..b56b6af 100644 (file)
@@ -231,7 +231,6 @@ FCFuncStart(gStringFuncs)
     FCFuncElement("IndexOfAny", COMString::IndexOfCharArray)
     FCFuncElement("LastIndexOf", COMString::LastIndexOfChar)
     FCFuncElement("LastIndexOfAny", COMString::LastIndexOfCharArray)
-    FCFuncElementSig("ReplaceInternal", &gsig_IM_Char_Char_RetStr, COMString::Replace)
     FCFuncElementSig("ReplaceInternal", &gsig_IM_Str_Str_RetStr, COMString::ReplaceString)
     FCFuncElement("PadHelper", COMString::PadHelper)
 #ifdef FEATURE_COMINTEROP