From 19984dd15b9bcd75dab098370e87848d12ab7577 Mon Sep 17 00:00:00 2001 From: Jack Del Vecchio Date: Mon, 28 Oct 2024 16:08:38 -0400 Subject: [PATCH] Optimize for case where no matches are found - Add additional parameter to replaceString that returns whether a match was found - Wait to allocate memory until a match is made rather than at the beginning of the search - Avoid copying source into result if source wasn't changed --- rtl/eclrtl/eclrtl.cpp | 8 +++++++- system/jlib/jstring.cpp | 28 +++++++++++++++++++--------- system/jlib/jstring.hpp | 2 +- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/rtl/eclrtl/eclrtl.cpp b/rtl/eclrtl/eclrtl.cpp index 156cad7066e..adca65d00bd 100644 --- a/rtl/eclrtl/eclrtl.cpp +++ b/rtl/eclrtl/eclrtl.cpp @@ -6066,7 +6066,13 @@ void rtlAddExceptionTag(StringBuffer & errorText, const char * tag, const char * void rtlSubstituteEmbeddedScript(size32_t &__lenResult, char * &__result, size32_t scriptChars, const char *script, size32_t outFieldsChars, const char *outFields, size32_t searchChars, const char *search) { StringBuffer result; - ::replaceString(result, rtlUtf8Size(scriptChars, script), script, rtlUtf8Size(searchChars, search), search, rtlUtf8Size(outFieldsChars, outFields), outFields); + bool foundMatch = false; + size_t sourceLen = rtlUtf8Size(scriptChars, script); + ::replaceString(result, sourceLen, script, rtlUtf8Size(searchChars, search), search, rtlUtf8Size(outFieldsChars, outFields), outFields, foundMatch); + + if (!foundMatch) + result.append(sourceLen, script); + __lenResult = result.lengthUtf8(); __result = result.detach(); } diff --git a/system/jlib/jstring.cpp b/system/jlib/jstring.cpp index 00e94ff1063..14e26205c1f 100644 --- a/system/jlib/jstring.cpp +++ b/system/jlib/jstring.cpp @@ -935,22 +935,28 @@ StringBuffer & StringBuffer::replace(char oldChar, char newChar) } // Copy source to result, replacing all occurrences of "oldStr" with "newStr" -StringBuffer &replaceString(StringBuffer & result, size_t lenSource, const char *source, size_t lenOldStr, const char* oldStr, size_t lenNewStr, const char* newStr) +StringBuffer &replaceString(StringBuffer & result, size_t lenSource, const char *source, size_t lenOldStr, const char* oldStr, size_t lenNewStr, const char* newStr, bool & foundMatch) { if (lenOldStr && lenSource >= lenOldStr) { - // Avoid allocating an unnecessarly large buffer and match the source string - result.ensureCapacity(lenSource); - size_t offset = 0; size_t lastCopied = 0; size_t maxOffset = lenSource - lenOldStr + 1; char firstChar = oldStr[0]; + foundMatch = false; while (offset < maxOffset) { if (unlikely(source[offset] == firstChar) && unlikely((lenOldStr == 1) || memcmp(source + offset, oldStr, lenOldStr)==0)) { + // Wait to allocate memory until a match is found + if (unlikely(!foundMatch)) + { + // Avoid allocating an unnecessarly large buffer and match the source string + result.ensureCapacity(lenSource); + foundMatch = true; + } + // If lastCopied matches the offset nothing is appended, but we can avoid a test for offset == lastCopied result.append(offset - lastCopied, source + lastCopied); result.append(lenNewStr, newStr); @@ -960,11 +966,10 @@ StringBuffer &replaceString(StringBuffer & result, size_t lenSource, const char else offset++; } - // Append the remaining characters - result.append(lenSource - lastCopied, source + lastCopied); + + if (foundMatch) + result.append(lenSource - lastCopied, source + lastCopied); // Append the remaining characters } - else - result.append(lenSource, source); // Search string does not fit in source or is empty return result; } @@ -1075,7 +1080,12 @@ StringBuffer & StringBuffer::replaceString(const char* oldStr, const char* newSt else { StringBuffer temp; - ::replaceString(temp, curLen, buffer, oldlen, oldStr, newlen, newStr); + bool foundMatch = false; + ::replaceString(temp, curLen, buffer, oldlen, oldStr, newlen, newStr, foundMatch); + + if (!foundMatch) + return *this; + swapWith(temp); } } diff --git a/system/jlib/jstring.hpp b/system/jlib/jstring.hpp index d61b7fb7a1f..6829827efdc 100644 --- a/system/jlib/jstring.hpp +++ b/system/jlib/jstring.hpp @@ -407,7 +407,7 @@ extern jlib_decl void decodeXML(ISimpleReadStream &in, StringBuffer &out, unsign extern jlib_decl int utf8CharLen(unsigned char ch); extern jlib_decl int utf8CharLen(const unsigned char *ch, unsigned maxsize = (unsigned)-1); -extern jlib_decl StringBuffer &replaceString(StringBuffer & result, size_t lenSource, const char *source, size_t lenOldStr, const char* oldStr, size_t lenNewStr, const char* newStr); +extern jlib_decl StringBuffer &replaceString(StringBuffer & result, size_t lenSource, const char *source, size_t lenOldStr, const char* oldStr, size_t lenNewStr, const char* newStr, bool & foundMatch); interface IVariableSubstitutionHelper {