diff options
| author | Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> | 2026-03-16 23:53:13 +0200 |
|---|---|---|
| committer | Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> | 2026-03-17 22:47:23 +0200 |
| commit | dd4f5cf13dbf9ec463bee2ce25e652786e5fb370 (patch) | |
| tree | b65c68f5c4f2f1e5a4b7b5c75204e69717a9086e | |
| parent | a5a6cfb995e9baed20980a67dfb89cacc6fe053c (diff) | |
viewer-private#540 Speed up url search #2
| -rw-r--r-- | indra/llui/llurlregistry.cpp | 77 |
1 files changed, 71 insertions, 6 deletions
diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index cb101d325d..8a21222b3c 100644 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -149,12 +149,77 @@ static bool stringHasUrl(const std::string &text) // fast heuristic test for a URL in a string. This is used // to avoid lots of costly regex calls, BUT it needs to be // kept in sync with the LLUrlEntry regexes we support. - return (text.find("://") != std::string::npos || - text.find("www.") != std::string::npos || - text.find(".com") != std::string::npos || - text.find("<nolink>") != std::string::npos || - text.find("<icon") != std::string::npos || - text.find("@") != std::string::npos); + + // Early exit for empty or very short strings + // Smallest url is 5 characters + if (text.length() < 3) + { + return false; + } + + // Single pass search for common URL indicators + for (size_t i = 0; i < text.length(); ++i) + { + char c = text[i]; + + // Check for @ (email or mention) + if (c == '@') + { + return true; + } + + if (i + 3 >= text.length()) + { + // Nothing else is going to match or fit if we don't + // have at least 4 characters left + // Ex: expectation is that there is something after protocol delimiter + // and .com takes 4 characters. + return false; + } + + // Check for protocol delimiter + if (c == ':' && text[i + 1] == '/' && text[i + 2] == '/') + { + return true; + } + + // Check for www. at start of word + if (c == 'w' + && text[i + 1] == 'w' + && text[i + 2] == 'w' + && text[i + 3] == '.') + { + return true; + } + + // Check for .com (and similar) + if (c == '.') + { + const char* suffix = text.c_str() + i + 1; + if ((suffix[0] == 'c' && suffix[1] == 'o' && suffix[2] == 'm') || + (suffix[0] == 'n' && suffix[1] == 'e' && suffix[2] == 't') || + (suffix[0] == 'o' && suffix[1] == 'r' && suffix[2] == 'g') || + (suffix[0] == 'e' && suffix[1] == 'd' && suffix[2] == 'u')) + { + return true; + } + } + + // Check for <nolink> or <icon + if (c == '<') + { + if (i + 7 < text.length() && text.compare(i + 1, 6, "nolink") == 0) + { + return true; + } + if (i + 4 < text.length() && text.compare(i + 1, 4, "icon") == 0) + { + return true; + } + } + } + + return false; } bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb, bool is_content_trusted, bool skip_non_mentions) |
