Skip to content

Commit 617a6df

Browse files
authored
Merge pull request #708 from LeanBitLab/bolt-optimize-is-regex-pattern-15896792960406868180
⚡ Bolt: Optimize regex pattern detection in DictionaryFacilitatorImpl
2 parents ece6fe1 + 65fdf15 commit 617a6df

2 files changed

Lines changed: 19 additions & 9 deletions

File tree

‎.jules/bolt.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,6 @@
2424
## 2024-05-18 - Optimize Diacritic Stripping in Suggest
2525
**Learning:** In `Suggest.isSameIgnoringAccents`, `val DIACRITIC_REGEX = "\\p{M}+".toRegex()` was being used in combination with `Normalizer.normalize` and `replace` to strip accents. This created string allocations via `Normalizer.normalize` and `Regex.replace` even for plain ASCII strings that lack accents, which is a hot path during typing and suggestion processing.
2626
**Action:** Replace `Regex.replace` with a manual character loop that avoids `Normalizer.normalize` entirely for pure ASCII strings and strips `Character.NON_SPACING_MARK` without regex allocation when normalizing.
27+
## 2024-05-18 - Optimize Regex pattern detection in DictionaryFacilitatorImpl
28+
**Learning:** `DictionaryFacilitatorImpl.isRegexPattern` used chained `String.contains()` and `String.startsWith()` calls, which internally execute full loops over the string (or delegate to regex). Replacing these chained calls with a single manual O(N) iteration reduces overhead and prevents repeatedly traversing the string.
29+
**Action:** Replace chained string detection methods (`contains`, `startsWith`, `endsWith`) with a single manual loop over the string's indices when checking multiple characters in performance hot paths.

‎app/src/main/java/helium314/keyboard/latin/DictionaryFacilitatorImpl.kt‎

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,15 +1235,22 @@ private class DictionaryGroup(
12351235
private var compiledBlacklistPatterns: List<Regex> = emptyList()
12361236

12371237
private fun isRegexPattern(pattern: String): Boolean {
1238-
return pattern.contains(".*")
1239-
|| pattern.contains(".+")
1240-
|| pattern.startsWith("^")
1241-
|| pattern.endsWith("$")
1242-
|| pattern.contains("[")
1243-
|| pattern.contains("(")
1244-
|| pattern.contains("\\")
1245-
|| pattern.contains("|")
1246-
|| pattern.contains("{")
1238+
if (pattern.isEmpty()) return false
1239+
val len = pattern.length
1240+
1241+
// ⚡ Bolt: Optimize regex pattern detection
1242+
// Replaced chained String.contains() and startsWith() calls with a single
1243+
// manual character iteration loop to reduce method overhead and execution time.
1244+
if (pattern[0] == '^' || pattern[len - 1] == '$') return true
1245+
for (i in 0 until len) {
1246+
val c = pattern[i]
1247+
if (c == '[' || c == '(' || c == '\\' || c == '|' || c == '{') return true
1248+
if (c == '.' && i + 1 < len) {
1249+
val next = pattern[i + 1]
1250+
if (next == '*' || next == '+') return true
1251+
}
1252+
}
1253+
return false
12471254
}
12481255

12491256
private fun rebuildCompiledPatterns() {

0 commit comments

Comments
 (0)