perf(core): use fixed-size ring vector for key lossage
ober
c31f23803c40df7bab48a3c645b9f47f1cba540a
--- a/src/jerboa-emacs/core.ss +++ b/src/jerboa-emacs/core.ss @@ -1409,9 +1409,9 @@ #f ; key-handler '() ; winner-history 0 ; winner-history-idx - (list (list "Tab 1" '("*scratch*") 0)) ; tabs - initial tab - 0 ; current-tab-idx - '())) ; key-lossage + (list (list "Tab 1" '("*scratch*") 0)) ; tabs - initial tab + 0 ; current-tab-idx + (make-key-lossage-ring))) ; key-lossage (def (get-prefix-arg app (default 1)) "Get the numeric value of the current prefix argument." @@ -1448,28 +1448,42 @@ (def *key-lossage-max* 300) +;; Lossage ring: vector #(buf head count) +;; buf — fixed vector of *key-lossage-max* slots (key string or #f) +;; head — index of the next write slot +;; count — number of valid entries (0..*key-lossage-max*) +;; Recording is O(1); no per-keystroke list copy. +(def (make-key-lossage-ring) + (vector (make-vector *key-lossage-max* #f) 0 0)) + (def (key-lossage-record! app key-str) "Record a keystroke in the lossage ring." - (let ((lossage (app-state-key-lossage app))) - (set! (app-state-key-lossage app) - (if (>= (length lossage) *key-lossage-max*) - (cons key-str (list-head lossage (- *key-lossage-max* 1))) - (cons key-str lossage))))) + (let* ((ring (app-state-key-lossage app)) + (buf (vector-ref ring 0)) + (head (vector-ref ring 1))) + (vector-set! buf head key-str) + (vector-set! ring 1 (modulo (+ head 1) *key-lossage-max*)) + (when (< (vector-ref ring 2) *key-lossage-max*) + (vector-set! ring 2 (+ (vector-ref ring 2) 1))))) (def (key-lossage->string app) "Format key lossage for display, 10 keys per line." - (let ((keys (reverse (app-state-key-lossage app)))) - (if (null? keys) + (let* ((ring (app-state-key-lossage app)) + (buf (vector-ref ring 0)) + (head (vector-ref ring 1)) + (count (vector-ref ring 2))) + (if (= count 0) "(no keystrokes recorded)" - (let loop ((ks keys) (col 0) (acc "")) - (if (null? ks) + (let loop ((i 0) (col 0) (acc "")) + (if (>= i count) acc - (let* ((k (car ks)) + (let* ((idx (modulo (+ (- head count) i) *key-lossage-max*)) + (k (vector-ref buf idx)) (sep (if (and (> col 0) (= (modulo col 10) 0)) "\n" " ")) (new-acc (if (string=? acc "") - k - (string-append acc sep k)))) - (loop (cdr ks) (+ col 1) new-acc))))))) + k + (string-append acc sep k)))) + (loop (+ i 1) (+ col 1) new-acc))))))) (def (list-head lst n) "Return the first n elements of lst."