Skip to content

Simplify internals and speed up per-file line/col computation - #11

Merged
dgageot merged 6 commits into
mainfrom
simplify-cleanups
Jul 24, 2026
Merged

Simplify internals and speed up per-file line/col computation#11
dgageot merged 6 commits into
mainfrom
simplify-cleanups

Conversation

@dgageot

@dgageot dgageot commented Jul 24, 2026

Copy link
Copy Markdown
Member

Several small internal cleanups landed together with one targeted performance fix in portcullis-scan.

On the simplification side, the nested sync.OnceValue inside rules was redundant because its only caller already memoises the result; rules is now a plain function. The two hand-unrolled five-word OR blocks in scanSerial duplicated kwMask.orIn, so they were replaced with a call to it; the hard-coded 320-pattern cap is now derived from len(kwMask{})*64 so it can't silently drift. A shared match-sort comparator is factored into sortMatches, and the repeated AC pre-filter prologue is factored into scanPrelude, both used by findMatches and Contains.

The performance change affects portcullis-scan: the old lineCol helper rescanned from offset 0 for every match, giving O(file × matches) work. Because matches arrive in ascending Start order, a single incremental cursor now walks each file once, giving identical output in a single pass.

All changes are behavior-preserving. go test ./..., go vet, and golangci-lint pass with zero issues; A/B benchmarks show no regression (identical allocations, timings within noise).

dgageot added 6 commits July 24, 2026 07:34
Its only caller, compiledRuleSet, is already memoised behind
sync.OnceValue, so the inner OnceValue wrapper added a layer of
indirection without saving any work.
… mask size

The two hand-unrolled OR blocks duplicated kwMask.orIn, which the
compiler already inlines to the same code (verified with -gcflags=-m
and A/B benchmarks). The 320-pattern cap is now computed from the
kwMask array length so it can't silently drift if the mask grows.
dedupOverlapping and mergeOverlapping used the same inline
comparator; a named helper documents the ordering contract once.
findMatches and Contains duplicated the empty-input check, rule-set
lookup, and keyword-mask early-out; one helper now owns that logic.
lineCol rescanned data from offset 0 for every match, making output
formatting O(len(file) x matches). Matches are emitted in ascending
Start order, so a single incremental cursor gives identical line and
column numbers in one pass.
…ne/col cursor

- kwMask doc and the overflow test no longer hardcode 320; both now
  track len(kwMask)*64 so they can't drift from buildAhoCorasick.
- scanPrelude doc mentions Redact, which also reaches it via
  findMatches.
- New table-driven scanFileBytes test locks down the incremental
  line/column cursor: match at offset zero, two matches on one line,
  CRLF endings, and empty files.
@dgageot
dgageot requested a review from a team as a code owner July 24, 2026 05:52
@dgageot
dgageot merged commit 713d04f into main Jul 24, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants