diff --git a/.jules/bolt.md b/.jules/bolt.md index c214509..4f3c926 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -21,3 +21,7 @@ ## 2025-05-10 - fmt.Sscanf is lenient, strconv.Atoi is strict **Learning:** In Go, `fmt.Sscanf("%d")` parses digits until it encounters a non-digit character (e.g., `"2beta"` parses as `2`), while `strconv.Atoi` fails and returns `0` for the entire string. If you need the lenient parsing behavior of `fmt.Sscanf` for performance optimization, implement a custom byte-traversal loop to extract leading digits rather than relying on `strconv.Atoi` or regex, as it is over 10x faster and maintains exact functional parity. **Action:** When replacing `fmt.Sscanf` for performance, always evaluate whether the leniency of the parser is being implicitly relied upon by the surrounding code. + +## 2024-06-10 - Avoid strings.Split in parsing loops +**Learning:** Using `strings.Split` in tight parsing loops (like version string comparisons) causes unnecessary slice allocations and degrades performance. +**Action:** To avoid this overhead and improve speed, use a `for` loop with `strings.Cut` to incrementally consume and parse the delimited string without allocating intermediate slices. diff --git a/internal/plugin/manager.go b/internal/plugin/manager.go index 7aad027..4ed4f8a 100644 --- a/internal/plugin/manager.go +++ b/internal/plugin/manager.go @@ -832,22 +832,23 @@ func parseLenientAtoi(s string) int { // CompareVersions compares two semver strings // Returns -1 if a < b, 0 if a == b, 1 if a > b func CompareVersions(a, b string) int { - partsA := strings.Split(a, ".") - partsB := strings.Split(b, ".") + for a != "" || b != "" { + var partA, partB string - maxLen := len(partsA) - if len(partsB) > maxLen { - maxLen = len(partsB) - } + if a != "" { + partA, a, _ = strings.Cut(a, ".") + } + if b != "" { + partB, b, _ = strings.Cut(b, ".") + } - for i := 0; i < maxLen; i++ { var numA, numB int - if i < len(partsA) { + if partA != "" { // Bolt optimization: using a custom loop is ~14x faster than fmt.Sscanf - numA = parseLenientAtoi(partsA[i]) + numA = parseLenientAtoi(partA) } - if i < len(partsB) { - numB = parseLenientAtoi(partsB[i]) + if partB != "" { + numB = parseLenientAtoi(partB) } if numA < numB { diff --git a/internal/update/update.go b/internal/update/update.go index 7bf6684..4b2637b 100644 --- a/internal/update/update.go +++ b/internal/update/update.go @@ -157,21 +157,22 @@ func fetchLatestVersion(ctx context.Context) (string, error) { } func compareVersions(a, b string) int { - partsA := strings.Split(a, ".") - partsB := strings.Split(b, ".") + for a != "" || b != "" { + var partA, partB string - maxLen := len(partsA) - if len(partsB) > maxLen { - maxLen = len(partsB) - } + if a != "" { + partA, a, _ = strings.Cut(a, ".") + } + if b != "" { + partB, b, _ = strings.Cut(b, ".") + } - for i := 0; i < maxLen; i++ { var numA, numB int - if i < len(partsA) { - numA, _ = strconv.Atoi(partsA[i]) + if partA != "" { + numA, _ = strconv.Atoi(partA) } - if i < len(partsB) { - numB, _ = strconv.Atoi(partsB[i]) + if partB != "" { + numB, _ = strconv.Atoi(partB) } if numA < numB {