diff options
| author | Andrey Lihatskiy <alihatskiy@productengine.com> | 2025-04-15 06:25:54 +0300 |
|---|---|---|
| committer | Andrey Lihatskiy <alihatskiy@productengine.com> | 2025-04-15 06:25:54 +0300 |
| commit | e9d6b27c381cdf0cc9406238bff1224b78c49cf5 (patch) | |
| tree | 887d43a7e3f74de095f89bf55ca02af75baa74c1 /indra/llui/llkeywords.cpp | |
| parent | 403fcb204381fd7a3d40f9924bfad498c3a17b6a (diff) | |
Optimize LLKeywords: pre-compile regex patterns
Diffstat (limited to 'indra/llui/llkeywords.cpp')
| -rw-r--r-- | indra/llui/llkeywords.cpp | 164 |
1 files changed, 95 insertions, 69 deletions
diff --git a/indra/llui/llkeywords.cpp b/indra/llui/llkeywords.cpp index 85f57b6548..19376ad8fa 100644 --- a/indra/llui/llkeywords.cpp +++ b/indra/llui/llkeywords.cpp @@ -282,6 +282,21 @@ void LLKeywords::processTokens() } } } + + // Pre-compile all regex patterns for tokens in mRegexTokenList + for (LLKeywordToken* regex_token : mRegexTokenList) + { + std::string start_pattern(regex_token->getToken().begin(), regex_token->getToken().end()); + try + { + regex_token->setCompiledRegex(new std::regex(start_pattern)); + } + catch (const std::regex_error& e) + { + LL_WARNS() << "Regex error in start pattern: " << e.what() << " in pattern: " << start_pattern << LL_ENDL; + } + } + LL_INFOS("SyntaxLSL") << "Finished processing tokens." << LL_ENDL; } @@ -599,99 +614,110 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW for (LLKeywordToken* regex_token : mRegexTokenList) { - std::string start_pattern(regex_token->getToken().begin(), regex_token->getToken().end()); - std::string end_pattern(regex_token->getDelimiter().begin(), regex_token->getDelimiter().end()); + std::regex* compiled_regex = regex_token->getCompiledRegex(); - try + // If we have a pre-compiled regex, use it + if (compiled_regex) { - std::regex start_regex_pattern(start_pattern); - std::smatch start_match; + std::string end_pattern(regex_token->getDelimiter().begin(), regex_token->getDelimiter().end()); - if (std::regex_search(text_to_search, start_match, start_regex_pattern) && !start_match.empty()) + try { - if (start_match.position() == 0) // Match starts at current position - { - // Calculate segment boundaries for start pattern - S32 start_match_length = static_cast<S32>(start_match.str().length()); - S32 start_seg_end = seg_start + start_match_length; - - if (end_pattern.empty()) - { - // If no end pattern is provided, treat the entire regex match as a single segment - // Move cursor past the matched segment - cur = base + start_seg_end; + std::smatch start_match; - // Insert the matched segment - insertSegments(wtext, *seg_list, regex_token, text_len, seg_start, start_seg_end, style, editor); - } - else + if (std::regex_search(text_to_search, start_match, *compiled_regex) && !start_match.empty()) + { + if (start_match.position() == 0) // Match starts at current position { - // Look for the end pattern after the start pattern - std::string remaining_text = text_to_search.substr(start_match_length); + // Calculate segment boundaries for start pattern + S32 start_match_length = static_cast<S32>(start_match.str().length()); + S32 start_seg_end = seg_start + start_match_length; - // Process end pattern - replace any capture group references - std::string actual_end_pattern = end_pattern; - - // Handle capture groups in the end pattern (replace \1, \2, etc. with their matched content) - for (size_t i = 1; i < start_match.size(); ++i) + if (end_pattern.empty()) { - std::string capture = start_match[i].str(); - std::string placeholder = "\\" + std::to_string(i); + // If no end pattern is provided, treat the entire regex match as a single segment + // Move cursor past the matched segment + cur = base + start_seg_end; - // Replace all occurrences of the placeholder with the captured content - size_t pos = 0; - while ((pos = actual_end_pattern.find(placeholder, pos)) != std::string::npos) - { - actual_end_pattern.replace(pos, placeholder.length(), capture); - pos += capture.length(); - } + // Insert the matched segment + insertSegments(wtext, *seg_list, regex_token, text_len, seg_start, start_seg_end, style, editor); } + else + { // TODO: better optimization for this part - try - { - std::regex end_regex_pattern(actual_end_pattern); - std::smatch end_match; + // Look for the end pattern after the start pattern + std::string remaining_text = text_to_search.substr(start_match_length); - S32 seg_end = start_seg_end; + // Process end pattern - replace any capture group references + std::string actual_end_pattern = end_pattern; - if (std::regex_search(remaining_text, end_match, end_regex_pattern) && !end_match.empty()) + // Handle capture groups in the end pattern (replace \1, \2, etc. with their matched content) + for (size_t i = 1; i < start_match.size(); ++i) { - // Calculate position of end match relative to the original text - S32 end_match_position = static_cast<S32>(end_match.position()); - S32 end_match_length = static_cast<S32>(end_match.str().length()); + std::string capture = start_match[i].str(); + std::string placeholder = "\\" + std::to_string(i); - // Calculate the total length including both patterns and text between - seg_end += end_match_position + end_match_length; + // Replace all occurrences of the placeholder with the captured content + size_t pos = 0; + while ((pos = actual_end_pattern.find(placeholder, pos)) != std::string::npos) + { + actual_end_pattern.replace(pos, placeholder.length(), capture); + pos += capture.length(); + } } - else + + try { - // End pattern not found, treat everything up to EOF as the segment - seg_end += static_cast<S32>(remaining_text.length()); - } + std::regex end_regex_pattern(actual_end_pattern); + std::smatch end_match; - // Move cursor past the entire matched segment (start + content + end) - cur = base + seg_end; + S32 seg_end = start_seg_end; - // Insert the matched segment - insertSegments(wtext, *seg_list, regex_token, text_len, seg_start, seg_end, style, editor); - } - catch (const std::regex_error& e) - { - LL_WARNS() << "Regex error in end pattern: " << e.what() << " in pattern: " << actual_end_pattern << LL_ENDL; - // Fall back to treating the start match as the entire segment - cur = base + start_seg_end; - insertSegments(wtext, *seg_list, regex_token, text_len, seg_start, start_seg_end, style, editor); + if (std::regex_search(remaining_text, end_match, end_regex_pattern) && !end_match.empty()) + { + // Calculate position of end match relative to the original text + S32 end_match_position = static_cast<S32>(end_match.position()); + S32 end_match_length = static_cast<S32>(end_match.str().length()); + + // Calculate the total length including both patterns and text between + seg_end += end_match_position + end_match_length; + } + else + { + // End pattern not found, treat everything up to EOF as the segment + seg_end += static_cast<S32>(remaining_text.length()); + } + + // Move cursor past the entire matched segment (start + content + end) + cur = base + seg_end; + + // Insert the matched segment + insertSegments(wtext, *seg_list, regex_token, text_len, seg_start, seg_end, style, editor); + } + catch (const std::regex_error& e) + { + LL_WARNS() << "Regex error in end pattern: " << e.what() << " in pattern: " << actual_end_pattern << LL_ENDL; + // Fall back to treating the start match as the entire segment + cur = base + start_seg_end; + insertSegments(wtext, *seg_list, regex_token, text_len, seg_start, start_seg_end, style, editor); + } } - } - regex_matched = true; - break; + regex_matched = true; + break; + } } } + catch (const std::regex_error& e) + { + LL_WARNS() << "Error using compiled regex: " << e.what() << LL_ENDL; + } } - catch (const std::regex_error& e) + else { - LL_WARNS() << "Regex error in start pattern: " << e.what() << " in pattern: " << start_pattern << LL_ENDL; + // Skip tokens that aren't pre-compiled + LL_WARNS() << "Skipping regex token due to missing pre-compiled pattern: " + << wstring_to_utf8str(regex_token->getToken()) << LL_ENDL; } } @@ -701,7 +727,7 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW } } - // If no regex match, check against delimiters + // Check against delimiters { S32 seg_start = 0; LLKeywordToken* cur_delimiter = NULL; |
