From a0b4443bc1806221dacdc409c8168eed7959e12d Mon Sep 17 00:00:00 2001 From: Bruce Bowyer-Smyth Date: Tue, 31 May 2016 16:38:35 +1000 Subject: [PATCH] Port String.IndexOf(char) and LastIndexOf(char) from CoreRT --- src/classlibnative/bcltype/stringnative.cpp | 93 --------------------- src/classlibnative/bcltype/stringnative.h | 4 - src/mscorlib/src/System/String.cs | 88 ++++++++++++++++++- src/vm/ecalllist.h | 2 - 4 files changed, 84 insertions(+), 103 deletions(-) diff --git a/src/classlibnative/bcltype/stringnative.cpp b/src/classlibnative/bcltype/stringnative.cpp index f75233902727..46be714ed3fe 100644 --- a/src/classlibnative/bcltype/stringnative.cpp +++ b/src/classlibnative/bcltype/stringnative.cpp @@ -342,49 +342,6 @@ FCIMPL5(INT32, COMString::CompareOrdinalEx, StringObject* strA, INT32 indexA, St } FCIMPLEND -/*=================================IndexOfChar================================== -**Action: -**Returns: -**Arguments: -**Exceptions: -==============================================================================*/ - -FCIMPL4 (INT32, COMString::IndexOfChar, StringObject* thisRef, CLR_CHAR value, INT32 startIndex, INT32 count ) -{ - FCALL_CONTRACT; - - VALIDATEOBJECT(thisRef); - if (thisRef==NULL) - FCThrow(kNullReferenceException); - - WCHAR *thisChars; - int thisLength; - - thisRef->RefInterpretGetStringValuesDangerousForGC(&thisChars, &thisLength); - - if (startIndex < 0 || startIndex > thisLength) { - FCThrowArgumentOutOfRange(W("startIndex"), W("ArgumentOutOfRange_Index")); - } - - if (count < 0 || count > thisLength - startIndex) { - FCThrowArgumentOutOfRange(W("count"), W("ArgumentOutOfRange_Count")); - } - - int endIndex = startIndex + count; - for (int i=startIndex; iRefInterpretGetStringValuesDangerousForGC(&thisChars, &thisLength); - - if (thisLength == 0) { - FC_GC_POLL_RET(); - return -1; - } - - - if (startIndex<0 || startIndex>=thisLength) { - FCThrowArgumentOutOfRange(W("startIndex"), W("ArgumentOutOfRange_Index")); - } - - if (count<0 || count - 1 > startIndex) { - FCThrowArgumentOutOfRange(W("count"), W("ArgumentOutOfRange_Count")); - } - - int endIndex = startIndex - count + 1; - - //We search [startIndex..EndIndex] - for (int i=startIndex; i>=endIndex; i--) { - if (thisChars[i]==((WCHAR)value)) { - FC_GC_POLL_RET(); - return i; - } - } - - FC_GC_POLL_RET(); - return -1; -} -FCIMPLEND /*=============================LastIndexOfCharArray============================= **Action: **Returns: diff --git a/src/classlibnative/bcltype/stringnative.h b/src/classlibnative/bcltype/stringnative.h index 751391ed5a9d..6d0d413c0d1a 100644 --- a/src/classlibnative/bcltype/stringnative.h +++ b/src/classlibnative/bcltype/stringnative.h @@ -61,10 +61,6 @@ class COMString { static FCDECL5(INT32, CompareOrdinalEx, StringObject* strA, INT32 indexA, StringObject* strB, INT32 indexB, INT32 count); - static FCDECL4(INT32, IndexOfChar, StringObject* vThisRef, CLR_CHAR value, INT32 startIndex, INT32 count ); - - static FCDECL4(INT32, LastIndexOfChar, StringObject* thisRef, CLR_CHAR value, INT32 startIndex, INT32 count ); - static FCDECL4(INT32, LastIndexOfCharArray, StringObject* thisRef, CHARArray* valueRef, INT32 startIndex, INT32 count ); static FCDECL4(INT32, IndexOfCharArray, StringObject* vThisRef, CHARArray* value, INT32 startIndex, INT32 count ); diff --git a/src/mscorlib/src/System/String.cs b/src/mscorlib/src/System/String.cs index cc69bfda7b3a..f9c7d5e4a999 100644 --- a/src/mscorlib/src/System/String.cs +++ b/src/mscorlib/src/System/String.cs @@ -2293,8 +2293,46 @@ public int IndexOf(char value, int startIndex) { [Pure] [System.Security.SecuritySafeCritical] // auto-generated - [MethodImplAttribute(MethodImplOptions.InternalCall)] - public extern int IndexOf(char value, int startIndex, int count); + public unsafe int IndexOf(char value, int startIndex, int count) { + if (startIndex < 0 || startIndex > Length) + throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index")); + + if (count < 0 || count > Length - startIndex) + throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count")); + + fixed (char* pChars = &m_firstChar) + { + char* pCh = pChars + startIndex; + + while (count >= 4) + { + if (*pCh == value) goto ReturnIndex; + if (*(pCh + 1) == value) goto ReturnIndex1; + if (*(pCh + 2) == value) goto ReturnIndex2; + if (*(pCh + 3) == value) goto ReturnIndex3; + + count -= 4; + pCh += 4; + } + + while (count > 0) + { + if (*pCh == value) + goto ReturnIndex; + + count--; + pCh++; + } + + return -1; + + ReturnIndex3: pCh++; + ReturnIndex2: pCh++; + ReturnIndex1: pCh++; + ReturnIndex: + return (int)(pCh - pChars); + } + } // Returns the index of the first occurrence of any specified character in the current instance. // The search starts at startIndex and runs to startIndex + count -1. @@ -2420,8 +2458,50 @@ public int LastIndexOf(char value, int startIndex){ [Pure] [System.Security.SecuritySafeCritical] // auto-generated - [MethodImplAttribute(MethodImplOptions.InternalCall)] - public extern int LastIndexOf(char value, int startIndex, int count); + public unsafe int LastIndexOf(char value, int startIndex, int count) { + if (Length == 0) + return -1; + + if (startIndex < 0 || startIndex >= Length) + throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index")); + + if (count < 0 || count - 1 > startIndex) + throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count")); + + fixed (char* pChars = &m_firstChar) + { + char* pCh = pChars + startIndex; + + //We search [startIndex..EndIndex] + while (count >= 4) + { + if (*pCh == value) goto ReturnIndex; + if (*(pCh - 1) == value) goto ReturnIndex1; + if (*(pCh - 2) == value) goto ReturnIndex2; + if (*(pCh - 3) == value) goto ReturnIndex3; + + count -= 4; + pCh -= 4; + } + + while (count > 0) + { + if (*pCh == value) + goto ReturnIndex; + + count--; + pCh--; + } + + return -1; + + ReturnIndex3: pCh--; + ReturnIndex2: pCh--; + ReturnIndex1: pCh--; + ReturnIndex: + return (int)(pCh - pChars); + } + } // Returns the index of the last occurrence of any specified character in the current instance. // The search starts at startIndex and runs backwards to startIndex - count + 1. diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h index 4307019a7f1c..dc9c432144f6 100644 --- a/src/vm/ecalllist.h +++ b/src/vm/ecalllist.h @@ -227,9 +227,7 @@ FCFuncStart(gStringFuncs) FCIntrinsic("get_Chars", COMString::GetCharAt, CORINFO_INTRINSIC_StringGetChar) FCFuncElement("IsAscii", COMString::IsAscii) FCFuncElement("nativeCompareOrdinalEx", COMString::CompareOrdinalEx) - FCFuncElement("IndexOf", COMString::IndexOfChar) FCFuncElement("IndexOfAny", COMString::IndexOfCharArray) - FCFuncElement("LastIndexOf", COMString::LastIndexOfChar) FCFuncElement("LastIndexOfAny", COMString::LastIndexOfCharArray) FCFuncElementSig("ReplaceInternal", &gsig_IM_Str_Str_RetStr, COMString::ReplaceString) #ifdef FEATURE_COMINTEROP