branch: externals/org
commit bc4ee1c72a638b815dd416b794e0666066a17122
Author: Ihor Radchenko <[email protected]>
Commit: Ihor Radchenko <[email protected]>

    org-element--current-element: Micro optimizations
    
    * lisp/org-element.el (org-element--current-element): Try hard
    spending minimal amount of time in testing which parser to call.
    Prefer `look-at-p' that does not modify match data and thus save us
    significant amount of time.  Do not call `org-with-limited-levels' and
    instead use the simplest possible tests with all unnecessary branches
    removed.  Add commentary explaining the importance of writing fast
    core when adding new elements.
    (org-inlinetask-min-level): Declare variable.
    
    * lisp/org-list.el (org--item-re-cache):
    (org-item-re): Cache results rather than calculating regexp every time
    the parser is invoked.
    * lisp/org-macs.el:
    (org--headline-re-cache):
    (org--headline-re-cache-no-bol):
    (org--headline-re-cache-bol):
    (org-headline-re): Prefer plists to store headline regexp cache - the
    number of items tends to be within 10-20 and hence hash table is an
    overkill and will be slower.
---
 lisp/org-element.el | 76 +++++++++++++++++++++++++++++------------------------
 lisp/org-list.el    | 32 ++++++++++++++++------
 lisp/org-macs.el    | 31 +++++++++++++++-------
 3 files changed, 88 insertions(+), 51 deletions(-)

diff --git a/lisp/org-element.el b/lisp/org-element.el
index ed740fc0b4..6d0890f4b5 100644
--- a/lisp/org-element.el
+++ b/lisp/org-element.el
@@ -4185,6 +4185,7 @@ Assume point is at the first equal sign marker."
 ;; It returns the Lisp representation of the element starting at
 ;; point.
 
+(defvar org-inlinetask-min-level); Declared in org-inlinetask.el
 (defvar org-element--cache-sync-requests); Declared later
 (defun org-element--current-element (limit &optional granularity mode 
structure add-to-cache)
   "Parse the element starting at point.
@@ -4247,30 +4248,40 @@ element it has to parse."
               result)
           (setq
            result
+           ;; Regexp matches below should avoid modifying match data,
+           ;; if possible.  Doing it unnecessarily degrades regexp
+           ;; matching performance an order of magnitude, which
+           ;; becomes important when parsing large buffers with huge
+           ;; amount of elements to be parsed.
+           ;;
+           ;; In general, the checks below should be as efficient as
+           ;; possible, especially early in the `cond' form.  (The
+           ;; early checks will contribute to al subsequent parsers as
+           ;; well).
            (cond
             ;; Item.
-            ((eq mode 'item)
-            (org-element-item-parser limit structure raw-secondary-p))
+            ((eq mode 'item) (org-element-item-parser limit structure 
raw-secondary-p))
             ;; Table Row.
             ((eq mode 'table-row) (org-element-table-row-parser limit))
             ;; Node Property.
             ((eq mode 'node-property) (org-element-node-property-parser limit))
             ;; Headline.
-            ((org-with-limited-levels (looking-at-p org-outline-regexp-bol))
+            ((and (looking-at-p "^\\*+ ")
+                  (or (not (featurep 'org-inlinetask))
+                      (save-excursion
+                        (< (skip-chars-forward "*")
+                           (if org-odd-levels-only
+                              (1- (* org-inlinetask-min-level 2))
+                            org-inlinetask-min-level)))))
              (org-element-headline-parser limit raw-secondary-p))
             ;; Sections (must be checked after headline).
-            ((eq mode 'section) (org-element-section-parser limit))
-            ((eq mode 'first-section)
-            (org-element-section-parser
-             (or (save-excursion (org-with-limited-levels 
(outline-next-heading)))
-                 limit)))
+            ((memq mode '(section first-section)) (org-element-section-parser 
nil))
             ;; Comments.
-            ((looking-at "^[ \t]*#\\(?: \\|$\\)")
-            (org-element-comment-parser limit))
+            ((looking-at-p "^[ \t]*#\\(?: \\|$\\)") 
(org-element-comment-parser limit))
             ;; Planning.
             ((and (eq mode 'planning)
                  (eq ?* (char-after (line-beginning-position 0)))
-                 (looking-at org-element-planning-line-re))
+                 (looking-at-p org-element-planning-line-re))
             (org-element-planning-parser limit))
             ;; Property drawer.
             ((and (pcase mode
@@ -4278,19 +4289,17 @@ element it has to parse."
                    ((or `property-drawer `top-comment)
                     (save-excursion
                       (beginning-of-line 0)
-                      (not (looking-at "[[:blank:]]*$"))))
+                      (not (looking-at-p "[[:blank:]]*$"))))
                    (_ nil))
-                 (looking-at org-property-drawer-re))
+                 (looking-at-p org-property-drawer-re))
             (org-element-property-drawer-parser limit))
             ;; When not at bol, point is at the beginning of an item or
             ;; a footnote definition: next item is always a paragraph.
             ((not (bolp)) (org-element-paragraph-parser limit (list (point))))
             ;; Clock.
-            ((looking-at org-element-clock-line-re)
-             (org-element-clock-parser limit))
+            ((looking-at-p org-element-clock-line-re) 
(org-element-clock-parser limit))
             ;; Inlinetask.
-            ((looking-at "^\\*+ ")
-            (org-element-inlinetask-parser limit raw-secondary-p))
+            ((looking-at-p "^\\*+ ") (org-element-inlinetask-parser limit 
raw-secondary-p))
             ;; From there, elements can have affiliated keywords.
             (t (let ((affiliated (org-element--collect-affiliated-keywords
                                  limit (memq granularity '(nil object)))))
@@ -4301,13 +4310,13 @@ element it has to parse."
                   (goto-char (car affiliated))
                   (org-element-keyword-parser limit nil))
                  ;; LaTeX Environment.
-                 ((looking-at org-element--latex-begin-environment)
+                 ((looking-at-p org-element--latex-begin-environment)
                   (org-element-latex-environment-parser limit affiliated))
                  ;; Drawer.
-                 ((looking-at org-element-drawer-re)
+                 ((looking-at-p org-element-drawer-re)
                   (org-element-drawer-parser limit affiliated))
                  ;; Fixed Width
-                 ((looking-at "[ \t]*:\\( \\|$\\)")
+                 ((looking-at-p "[ \t]*:\\( \\|$\\)")
                   (org-element-fixed-width-parser limit affiliated))
                  ;; Inline Comments, Blocks, Babel Calls, Dynamic Blocks and
                  ;; Keywords.
@@ -4327,31 +4336,31 @@ element it has to parse."
                                (_         #'org-element-special-block-parser))
                              limit
                              affiliated))
-                   ((looking-at "CALL:")
+                   ((looking-at-p "CALL:")
                     (beginning-of-line)
                     (org-element-babel-call-parser limit affiliated))
                    ((save-excursion
                        (beginning-of-line)
-                       (looking-at org-element-dynamic-block-open-re))
+                       (looking-at-p org-element-dynamic-block-open-re))
                     (beginning-of-line)
                     (org-element-dynamic-block-parser limit affiliated))
-                   ((looking-at "\\S-+:")
+                   ((looking-at-p "\\S-+:")
                     (beginning-of-line)
                     (org-element-keyword-parser limit affiliated))
                    (t
                     (beginning-of-line)
                     (org-element-paragraph-parser limit affiliated))))
                  ;; Footnote Definition.
-                 ((looking-at org-footnote-definition-re)
+                 ((looking-at-p org-footnote-definition-re)
                   (org-element-footnote-definition-parser limit affiliated))
                  ;; Horizontal Rule.
-                 ((looking-at "[ \t]*-\\{5,\\}[ \t]*$")
+                 ((looking-at-p "[ \t]*-\\{5,\\}[ \t]*$")
                   (org-element-horizontal-rule-parser limit affiliated))
                  ;; Diary Sexp.
-                 ((looking-at "%%(")
+                 ((looking-at-p "%%(")
                   (org-element-diary-sexp-parser limit affiliated))
                  ;; Table.
-                 ((or (looking-at "[ \t]*|")
+                 ((or (looking-at-p "[ \t]*|")
                       ;; There is no strict definition of a table.el
                       ;; table.  Try to prevent false positive while being
                       ;; quick.
@@ -4368,7 +4377,7 @@ element it has to parse."
                             (next (line-beginning-position 2)))
                         ;; Start with a full rule.
                         (and
-                         (looking-at rule-regexp)
+                         (looking-at-p rule-regexp)
                          (< next limit) ;no room for a table.el table
                          (save-excursion
                            (end-of-line)
@@ -4376,7 +4385,7 @@ element it has to parse."
                             ;; Must end with a full rule.
                             ((not (re-search-forward non-table.el-line limit 
'move))
                              (if (bolp) (forward-line -1) (beginning-of-line))
-                             (looking-at rule-regexp))
+                             (looking-at-p rule-regexp))
                             ;; Ignore pseudo-tables with a single
                             ;; rule.
                             ((= next (line-beginning-position))
@@ -4384,10 +4393,10 @@ element it has to parse."
                             ;; Must end with a full rule.
                             (t
                              (forward-line -1)
-                             (looking-at rule-regexp)))))))
+                             (looking-at-p rule-regexp)))))))
                   (org-element-table-parser limit affiliated))
                  ;; List.
-                 ((looking-at (org-item-re))
+                 ((looking-at-p (org-item-re))
                   (org-element-plain-list-parser
                    limit affiliated
                    (or structure (org-element--list-struct limit))))
@@ -4396,10 +4405,9 @@ element it has to parse."
           (when result
             (org-element-put-property result :mode mode)
             (org-element-put-property result :granularity granularity))
-          (when (and (not (buffer-narrowed-p))
-                     (org-element--cache-active-p)
+          (when (and add-to-cache(not (buffer-narrowed-p))
                      (not org-element--cache-sync-requests)
-                     add-to-cache)
+                     (org-element--cache-active-p))
             (if (not old-element)
                 (setq result (org-element--cache-put result))
               (org-element-set-element old-element result)
diff --git a/lisp/org-list.el b/lisp/org-list.el
index 0e52e99550..dbbacaeba0 100644
--- a/lisp/org-list.el
+++ b/lisp/org-list.el
@@ -364,16 +364,32 @@ group 2: counter
 group 3: checkbox
 group 4: description tag")
 
+(defvar org--item-re-cache nil
+  "Results cache for `org-item-re'.")
 (defun org-item-re ()
   "Return the correct regular expression for plain lists."
-  (let ((term (cond
-              ((eq org-plain-list-ordered-item-terminator t) "[.)]")
-              ((= org-plain-list-ordered-item-terminator ?\)) ")")
-              ((= org-plain-list-ordered-item-terminator ?.) "\\.")
-              (t "[.)]")))
-       (alpha (if org-list-allow-alphabetical "\\|[A-Za-z]" "")))
-    (concat "\\([ \t]*\\([-+]\\|\\(\\([0-9]+" alpha "\\)" term
-           "\\)\\)\\|[ \t]+\\*\\)\\([ \t]+\\|$\\)")))
+  (or (plist-get
+       (plist-get org--item-re-cache
+                  org-list-allow-alphabetical)
+       org-plain-list-ordered-item-terminator)
+      (let* ((term (cond
+                   ((eq org-plain-list-ordered-item-terminator t) "[.)]")
+                   ((= org-plain-list-ordered-item-terminator ?\)) ")")
+                   ((= org-plain-list-ordered-item-terminator ?.) "\\.")
+                   (t "[.)]")))
+            (alpha (if org-list-allow-alphabetical "\\|[A-Za-z]" ""))
+             (re (concat "\\([ \t]*\\([-+]\\|\\(\\([0-9]+" alpha "\\)" term
+                        "\\)\\)\\|[ \t]+\\*\\)\\([ \t]+\\|$\\)")))
+        (setq org--item-re-cache
+              (plist-put
+               org--item-re-cache
+               org-list-allow-alphabetical
+               (plist-put
+                (plist-get org--item-re-cache
+                           org-list-allow-alphabetical)
+                org-plain-list-ordered-item-terminator
+                re)))
+        re)))
 
 (defsubst org-item-beginning-re ()
   "Regexp matching the beginning of a plain list item."
diff --git a/lisp/org-macs.el b/lisp/org-macs.el
index f771c408b3..06fbc0d64c 100644
--- a/lisp/org-macs.el
+++ b/lisp/org-macs.el
@@ -807,20 +807,33 @@ get an unnecessary O(N²) space complexity, so you're 
usually better off using
       (eval form t)
     (error (format "%%![Error: %s]" error))))
 
-(defvar org--headline-re-cache (make-hash-table :test #'equal)
-  "Hash table holding association between headline level regexp.")
+(defvar org--headline-re-cache-no-bol nil
+  "Plist holding association between headline level regexp.")
+(defvar org--headline-re-cache-bol nil
+  "Plist holding association between headline level regexp.")
 (defun org-headline-re (true-level &optional no-bol)
   "Generate headline regexp for TRUE-LEVEL.
 When NO-BOL is non-nil, regexp will not demand the regexp to start at
 beginning of line."
-  (or (gethash (cons true-level no-bol) org--headline-re-cache)
-      (puthash
-       (cons true-level no-bol)
-       (rx-to-string
+  (or (plist-get
+       (if no-bol
+           org--headline-re-cache-no-bol
+         org--headline-re-cache-bol)
+       true-level)
+      (let ((re (rx-to-string
+                 (if no-bol
+                     `(seq (** 1 ,true-level "*") " ")
+                   `(seq line-start (** 1 ,true-level "*") " ")))))
         (if no-bol
-            `(seq (** 1 ,true-level "*") " ")
-          `(seq line-start (** 1 ,true-level "*") " ")))
-       org--headline-re-cache)))
+            (setq org--headline-re-cache-no-bol
+                  (plist-put
+                   org--headline-re-cache-no-bol
+                   true-level re))
+          (setq org--headline-re-cache-bol
+                (plist-put
+                 org--headline-re-cache-bol
+                 true-level re)))
+        re)))
 
 (defvar org-outline-regexp) ; defined in org.el
 (defvar org-outline-regexp-bol) ; defined in org.el

Reply via email to