Skip to content

Commit

Permalink
Optimize for case where no matches are found
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
jackdelv committed Oct 28, 2024
1 parent 98315c6 commit 19984dd
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 11 deletions.
8 changes: 7 additions & 1 deletion rtl/eclrtl/eclrtl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
28 changes: 19 additions & 9 deletions system/jlib/jstring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
}
}
Expand Down
2 changes: 1 addition & 1 deletion system/jlib/jstring.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down

0 comments on commit 19984dd

Please sign in to comment.