Skip to content

Commit 8ce5e37

Browse files
author
Alan Mackenzie
committed
Optimize CC Mode a bit for repetitive insertion and replace-regexp
This is mainly by enhancing a parse-partial-sexp cache to retain recently calculated values. Also, there are several miscellaneous optimizations and bug fixes. * lisp/progmodes/cc-engine.el (c-state-semi-nonlit-near-cache): New buffer local variable. (c-state-semi-trim-near-cache, c-state-semi-get-near-cache-entry) (c-state-semi-put-near-cache-entry, c-state-semi-trim-cache): New functions. (c-state-semi-pp-to-literal, c-state-full-pp-to-literal): Use the new "near" cache. (c-parse-ps-state-below): Use the new function c-state-semi-trim-cache. (c-before-change-check-<>-operators): Check simply for < or > in the neighbourhood before doing more expensive processing. (c-maybe-re-mark-raw-string): Give a backward search limit to an operation which was needlessly lacking one. * lisp/progmodes/cc-mode.el (c-doc-fl-decl-start, c-doc-fl-decl-end): Check a certain regexp is valid before performing the (somewhat expensive) actions of these functions. (c-fl-decl-start): In the search for a C++ lambda capture list, replace (slow) calculation of c-parse-state by a (less slow) c-go-up-list-backward.
1 parent a8d17f3 commit 8ce5e37

File tree

2 files changed

+186
-74
lines changed

2 files changed

+186
-74
lines changed

lisp/progmodes/cc-engine.el

Lines changed: 164 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2526,6 +2526,25 @@ comment at the start of cc-engine.el for more info."
25262526
;; reduced by buffer changes, and increased by invocations of
25272527
;; `c-state-literal-at'.
25282528

2529+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2530+
;; We also maintain a less simple cache of positions which aren't in a
2531+
;; literal, disregarding macros.
2532+
;;
2533+
;; This cache is in two parts: the "near" cache, which is an association list
2534+
;; of a small number (currently six) of positions and the parser states there;
2535+
;; the "far" cache (also known as "the cache"), a list of compressed parser
2536+
;; states going back to the beginning of the buffer, one entry every 3000
2537+
;; characters.
2538+
;;
2539+
;; When searching this cache, `c-state-semi-pp-to-literal' first seeks an
2540+
;; exact match, then a "close" match from the near cache. If neither of these
2541+
;; succeed, the nearest entry in the far cache is used.
2542+
;;
2543+
;; Because either sub-cache can raise `c-state-semi-nonlit-pos-cache-limit',
2544+
;; both of them are "trimmed" together after a buffer change to ensure
2545+
;; consistency.
2546+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2547+
25292548
(defvar c-state-semi-nonlit-pos-cache nil)
25302549
(make-variable-buffer-local 'c-state-semi-nonlit-pos-cache)
25312550
;; A list of elements which are either buffer positions (when such positions
@@ -2539,12 +2558,62 @@ comment at the start of cc-engine.el for more info."
25392558
;; is reduced by buffer changes, and increased by invocations of
25402559
;; `c-parse-ps-state-below'.
25412560

2561+
(defvar c-state-semi-nonlit-near-cache nil)
2562+
(make-variable-buffer-local 'c-state-semi-nonlit-near-cache)
2563+
;; A list of up to six recent results from `c-state-semi-pp-to-literal'. Each
2564+
;; element is a cons of the buffer position and the `parse-partial-sexp' state
2565+
;; at that position.
2566+
25422567
(defsubst c-truncate-semi-nonlit-pos-cache (pos)
25432568
;; Truncate the upper bound of the cache `c-state-semi-nonlit-pos-cache' to
25442569
;; POS, if it is higher than that position.
25452570
(setq c-state-semi-nonlit-pos-cache-limit
25462571
(min c-state-semi-nonlit-pos-cache-limit pos)))
25472572

2573+
(defun c-state-semi-trim-near-cache ()
2574+
;; Remove stale entries in `c-state-semi-nonlit-near-cache', i.e. those
2575+
;; whose positions are above `c-state-semi-nonlit-pos-cache-limit'.
2576+
(let ((nc-list c-state-semi-nonlit-near-cache))
2577+
(while nc-list
2578+
(if (> (caar nc-list) c-state-semi-nonlit-pos-cache-limit)
2579+
(setq c-state-semi-nonlit-near-cache
2580+
(delq (car nc-list) c-state-semi-nonlit-near-cache)
2581+
nc-list c-state-semi-nonlit-near-cache) ; start again in case
2582+
; of list breakage.
2583+
(setq nc-list (cdr nc-list))))))
2584+
2585+
(defun c-state-semi-get-near-cache-entry (here)
2586+
;; Return the near cache entry at the highest postion before HERE, if any,
2587+
;; or nil. The near cache entry is of the form (POSITION . STATE), where
2588+
;; STATE has the form of a result of `parse-partial-sexp'.
2589+
(let ((nc-pos-state
2590+
(or (assq here c-state-semi-nonlit-near-cache)
2591+
(let ((nc-list c-state-semi-nonlit-near-cache)
2592+
pos (nc-pos 0) cand-pos-state)
2593+
(while nc-list
2594+
(setq pos (caar nc-list))
2595+
(when (and (<= pos here)
2596+
(> pos nc-pos))
2597+
(setq nc-pos pos
2598+
cand-pos-state (car nc-list)))
2599+
(setq nc-list (cdr nc-list)))
2600+
cand-pos-state))))
2601+
(when (and nc-pos-state
2602+
(not (eq nc-pos-state (car c-state-semi-nonlit-near-cache))))
2603+
;; Move the found cache entry to the front of the list.
2604+
(setq c-state-semi-nonlit-near-cache
2605+
(delq nc-pos-state c-state-semi-nonlit-near-cache))
2606+
(push nc-pos-state c-state-semi-nonlit-near-cache))
2607+
nc-pos-state))
2608+
2609+
(defun c-state-semi-put-near-cache-entry (here state)
2610+
;; Put a new near cache entry into the near cache.
2611+
(while (>= (length c-state-semi-nonlit-near-cache) 6)
2612+
(setq c-state-semi-nonlit-near-cache
2613+
(delq (car (last c-state-semi-nonlit-near-cache))
2614+
c-state-semi-nonlit-near-cache)))
2615+
(push (cons here state) c-state-semi-nonlit-near-cache))
2616+
25482617
(defun c-state-semi-pp-to-literal (here &optional not-in-delimiter)
25492618
;; Do a parse-partial-sexp from a position in the buffer before HERE which
25502619
;; isn't in a literal, and return information about HERE, either:
@@ -2564,12 +2633,28 @@ comment at the start of cc-engine.el for more info."
25642633
(save-excursion
25652634
(save-restriction
25662635
(widen)
2636+
(c-state-semi-trim-cache)
2637+
(c-state-semi-trim-near-cache)
2638+
(setq c-state-semi-nonlit-pos-cache-limit here)
25672639
(save-match-data
2568-
(let* ((base-and-state (c-parse-ps-state-below here))
2640+
(let* ((base-and-state (c-state-semi-get-near-cache-entry here))
25692641
(base (car base-and-state))
2642+
(near-base base)
25702643
(s (cdr base-and-state))
2571-
(s (parse-partial-sexp base here nil nil s))
2572-
ty)
2644+
far-base-and-state far-base far-s ty)
2645+
(if (or (not base)
2646+
(< base (- here 100)))
2647+
(progn
2648+
(setq far-base-and-state (c-parse-ps-state-below here)
2649+
far-base (car far-base-and-state)
2650+
far-s (cdr far-base-and-state))
2651+
(when (or (not base) (> far-base base))
2652+
(setq base far-base
2653+
s far-s))))
2654+
(when (> here base)
2655+
(setq s (parse-partial-sexp base here nil nil s)))
2656+
(when (not (eq near-base here))
2657+
(c-state-semi-put-near-cache-entry here s))
25732658
(cond
25742659
((or (nth 3 s)
25752660
(and (nth 4 s)
@@ -2612,12 +2697,28 @@ comment at the start of cc-engine.el for more info."
26122697
(save-excursion
26132698
(save-restriction
26142699
(widen)
2700+
(c-state-semi-trim-cache)
2701+
(c-state-semi-trim-near-cache)
2702+
(setq c-state-semi-nonlit-pos-cache-limit here)
26152703
(save-match-data
2616-
(let* ((base-and-state (c-parse-ps-state-below here))
2704+
(let* ((base-and-state (c-state-semi-get-near-cache-entry here))
26172705
(base (car base-and-state))
2706+
(near-base base)
26182707
(s (cdr base-and-state))
2619-
(s (parse-partial-sexp base here nil nil s))
2620-
ty start)
2708+
far-base-and-state far-base far-s ty start)
2709+
(if (or (not base)
2710+
(< base (- here 100)))
2711+
(progn
2712+
(setq far-base-and-state (c-parse-ps-state-below here)
2713+
far-base (car far-base-and-state)
2714+
far-s (cdr far-base-and-state))
2715+
(when (or (not base) (> far-base base))
2716+
(setq base far-base
2717+
s far-s))))
2718+
(when (> here base)
2719+
(setq s (parse-partial-sexp base here nil nil s)))
2720+
(when (not (eq near-base here))
2721+
(c-state-semi-put-near-cache-entry here s))
26212722
(cond
26222723
((or (nth 3 s)
26232724
(and (nth 4 s)
@@ -2812,6 +2913,14 @@ comment at the start of cc-engine.el for more info."
28122913
elt
28132914
(car elt)))
28142915

2916+
(defun c-state-semi-trim-cache ()
2917+
;; Trim the `c-state-semi-nonlit-pos-cache' to take account of buffer
2918+
;; changes, indicated by `c-state-semi-nonlit-pos-cache-limit'.
2919+
(while (and c-state-semi-nonlit-pos-cache
2920+
(> (c-ps-state-cache-pos (car c-state-semi-nonlit-pos-cache))
2921+
c-state-semi-nonlit-pos-cache-limit))
2922+
(setq c-state-semi-nonlit-pos-cache (cdr c-state-semi-nonlit-pos-cache))))
2923+
28152924
(defun c-parse-ps-state-below (here)
28162925
;; Given a buffer position HERE, Return a cons (CACHE-POS . STATE), where
28172926
;; CACHE-POS is a position not very far before HERE for which the
@@ -2822,14 +2931,9 @@ comment at the start of cc-engine.el for more info."
28222931
(save-excursion
28232932
(save-restriction
28242933
(widen)
2934+
(c-state-semi-trim-cache)
28252935
(let ((c c-state-semi-nonlit-pos-cache)
28262936
elt state npos high-elt)
2827-
;; Trim the cache to take account of buffer changes.
2828-
(while (and c (> (c-ps-state-cache-pos (car c))
2829-
c-state-semi-nonlit-pos-cache-limit))
2830-
(setq c (cdr c)))
2831-
(setq c-state-semi-nonlit-pos-cache c)
2832-
28332937
(while (and c (> (c-ps-state-cache-pos (car c)) here))
28342938
(setq high-elt (car c))
28352939
(setq c (cdr c)))
@@ -5617,7 +5721,7 @@ comment at the start of cc-engine.el for more info."
56175721
(when (not high-elt)
56185722
(setq stack (cdr elt))
56195723
(while
5620-
;; Add an element to `c-state-semi-nonlit-pos-cache' each iteration.
5724+
;; Add an element to `c-bs-cache' each iteration.
56215725
(<= (setq npos (+ pos c-bs-interval)) here)
56225726
(setq elt (c-update-brace-stack stack pos npos))
56235727
(setq npos (car elt))
@@ -6469,44 +6573,52 @@ comment at the start of cc-engine.el for more info."
64696573
;;
64706574
;; FIXME!!! This routine ignores the possibility of macros entirely.
64716575
;; 2010-01-29.
6472-
(save-excursion
6473-
(c-save-buffer-state
6474-
((beg-lit-start (progn (goto-char beg) (c-literal-start)))
6475-
(end-lit-limits (progn (goto-char end) (c-literal-limits)))
6476-
new-beg new-end beg-limit end-limit)
6477-
;; Locate the earliest < after the barrier before the changed region,
6478-
;; which isn't already marked as a paren.
6479-
(goto-char (or beg-lit-start beg))
6480-
(setq beg-limit (c-determine-limit 512))
6481-
6482-
;; Remove the syntax-table/category properties from each pertinent <...>
6483-
;; pair. Firstly, the ones with the < before beg and > after beg....
6484-
(while (progn (c-syntactic-skip-backward "^;{}<" beg-limit)
6485-
(eq (char-before) ?<))
6486-
(c-backward-token-2)
6487-
(when (eq (char-after) ?<)
6488-
(c-clear-<-pair-props-if-match-after beg)
6489-
(setq new-beg (point))))
6490-
(c-forward-syntactic-ws)
6576+
(when (and (> end beg)
6577+
(or
6578+
(progn
6579+
(goto-char beg)
6580+
(search-backward "<" (max (- (point) 1024) (point-min)) t))
6581+
(progn
6582+
(goto-char end)
6583+
(search-forward ">" (min (+ (point) 1024) (point-max)) t))))
6584+
(save-excursion
6585+
(c-save-buffer-state
6586+
((beg-lit-start (progn (goto-char beg) (c-literal-start)))
6587+
(end-lit-limits (progn (goto-char end) (c-literal-limits)))
6588+
new-beg new-end beg-limit end-limit)
6589+
;; Locate the earliest < after the barrier before the changed region,
6590+
;; which isn't already marked as a paren.
6591+
(goto-char (or beg-lit-start beg))
6592+
(setq beg-limit (c-determine-limit 512))
6593+
6594+
;; Remove the syntax-table/category properties from each pertinent <...>
6595+
;; pair. Firstly, the ones with the < before beg and > after beg....
6596+
(while (progn (c-syntactic-skip-backward "^;{}<" beg-limit)
6597+
(eq (char-before) ?<))
6598+
(c-backward-token-2)
6599+
(when (eq (char-after) ?<)
6600+
(c-clear-<-pair-props-if-match-after beg)
6601+
(setq new-beg (point))))
6602+
(c-forward-syntactic-ws)
64916603

6492-
;; ...Then the ones with < before end and > after end.
6493-
(goto-char (if end-lit-limits (cdr end-lit-limits) end))
6494-
(setq end-limit (c-determine-+ve-limit 512))
6495-
(while (and (c-syntactic-re-search-forward "[;{}>]" end-limit 'end)
6496-
(eq (char-before) ?>))
6497-
(c-end-of-current-token)
6498-
(when (eq (char-before) ?>)
6499-
(c-clear->-pair-props-if-match-before end (1- (point)))
6500-
(setq new-end (point))))
6501-
(c-backward-syntactic-ws)
6502-
6503-
;; Extend the fontification region, if needed.
6504-
(and new-beg
6505-
(< new-beg c-new-BEG)
6506-
(setq c-new-BEG new-beg))
6507-
(and new-end
6508-
(> new-end c-new-END)
6509-
(setq c-new-END new-end)))))
6604+
;; ...Then the ones with < before end and > after end.
6605+
(goto-char (if end-lit-limits (cdr end-lit-limits) end))
6606+
(setq end-limit (c-determine-+ve-limit 512))
6607+
(while (and (c-syntactic-re-search-forward "[;{}>]" end-limit 'end)
6608+
(eq (char-before) ?>))
6609+
(c-end-of-current-token)
6610+
(when (eq (char-before) ?>)
6611+
(c-clear->-pair-props-if-match-before end (1- (point)))
6612+
(setq new-end (point))))
6613+
(c-backward-syntactic-ws)
6614+
6615+
;; Extend the fontification region, if needed.
6616+
(and new-beg
6617+
(< new-beg c-new-BEG)
6618+
(setq c-new-BEG new-beg))
6619+
(and new-end
6620+
(> new-end c-new-END)
6621+
(setq c-new-END new-end))))))
65106622

65116623
(defun c-after-change-check-<>-operators (beg end)
65126624
;; This is called from `after-change-functions' when
@@ -7123,7 +7235,8 @@ comment at the start of cc-engine.el for more info."
71237235
t)
71247236
((save-excursion
71257237
(and
7126-
(search-backward-regexp ")\\([^ ()\\\n\r\t]\\{0,16\\}\\)\"\\=" nil t)
7238+
(search-backward-regexp ")\\([^ ()\\\n\r\t]\\{0,16\\}\\)\"\\="
7239+
(c-point 'bol) t)
71277240
(setq id (match-string-no-properties 1))
71287241
(let* ((quoted-id (regexp-quote id))
71297242
(quoted-id-depth (regexp-opt-depth quoted-id)))

lisp/progmodes/cc-mode.el

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1825,28 +1825,30 @@ Note that this is a strict tail, so won't match, e.g. \"0x....\".")
18251825
;; by `c-doc-line-join-re'), return the position of the first line of the
18261826
;; sequence. Otherwise, return nil. Point has no significance at entry to
18271827
;; and exit from this function.
1828-
(goto-char pos)
1829-
(back-to-indentation)
1830-
(and (or (looking-at c-comment-start-regexp)
1831-
(memq (c-literal-type (c-literal-limits)) '(c c++)))
1832-
(progn
1833-
(end-of-line)
1834-
(let ((here (point)))
1835-
(while (re-search-backward c-doc-line-join-re (c-point 'bopl) t))
1836-
(and (not (eq (point) here))
1837-
(c-point 'bol))))))
1828+
(when (not (equal c-doc-line-join-re "a\\`"))
1829+
(goto-char pos)
1830+
(back-to-indentation)
1831+
(and (or (looking-at c-comment-start-regexp)
1832+
(memq (c-literal-type (c-literal-limits)) '(c c++)))
1833+
(progn
1834+
(end-of-line)
1835+
(let ((here (point)))
1836+
(while (re-search-backward c-doc-line-join-re (c-point 'bopl) t))
1837+
(and (not (eq (point) here))
1838+
(c-point 'bol)))))))
18381839

18391840
(defun c-doc-fl-decl-end (pos)
18401841
;; If the line containing POS is continued by a doc comment continuation
18411842
;; marker (as defined by `c-doc-line-join-re), return the position of
18421843
;; the BOL at the end of the sequence. Otherwise, return nil. Point has no
18431844
;; significance at entry to and exit from this function.
1844-
(goto-char pos)
1845-
(back-to-indentation)
1846-
(let ((here (point)))
1847-
(while (re-search-forward c-doc-line-join-re (c-point 'eonl) t))
1848-
(and (not (eq (point) here))
1849-
(c-point 'bonl))))
1845+
(when (not (equal c-doc-line-join-re "a\\`"))
1846+
(goto-char pos)
1847+
(back-to-indentation)
1848+
(let ((here (point)))
1849+
(while (re-search-forward c-doc-line-join-re (c-point 'eonl) t))
1850+
(and (not (eq (point) here))
1851+
(c-point 'bonl)))))
18501852

18511853
(defun c-fl-decl-start (pos)
18521854
;; If the beginning of the line containing POS is in the middle of a "local"
@@ -1874,13 +1876,10 @@ Note that this is a strict tail, so won't match, e.g. \"0x....\".")
18741876
;; In C++ Mode, first check if we are within a (possibly nested) lambda
18751877
;; form capture list.
18761878
(when (c-major-mode-is 'c++-mode)
1877-
(let ((paren-state (c-parse-state))
1878-
opener)
1879-
(save-excursion
1880-
(while (setq opener (c-pull-open-brace paren-state))
1881-
(goto-char opener)
1882-
(if (c-looking-at-c++-lambda-capture-list)
1883-
(setq capture-opener (point)))))))
1879+
(save-excursion
1880+
(while (and (c-go-up-list-backward nil bod-lim)
1881+
(c-looking-at-c++-lambda-capture-list))
1882+
(setq capture-opener (point)))))
18841883

18851884
(while
18861885
;; Go to a less nested declaration each time round this loop.

0 commit comments

Comments
 (0)