> Please use double space between sentences and `quote' like this, not
> `like this`. See https://orgmode.org/worg/org-contribute.html#commit-messages

fixed

>> Second, the loop was much more complex than needed. The loop included
>> :standard-properties which should not be necessary here. It also
>> duplicated some work between calls to `org-element--properties-mapc`
>> and `mapconcat` (the code was moved entirely under the former). The
>> result should be faster and more readable.
>
> This part of the commit message should probably be dropped as you
> removed this part from the code.

fixed

> This is not TINYCHANGE as it is a lot more than 15LOC.

fixed

> Now, you no longer need to call internal function. Just use
> `org-element-properties-mapc'.

fixed, although I wasn't sure if 'force should be used here

>From 0e32e35dcf6e99f5a840872192f7e2cb50673f0c Mon Sep 17 00:00:00 2001
From: ndwarshuis <nd...@yavin4.ch>
Date: Mon, 25 Nov 2024 22:04:09 -0500
Subject: [PATCH] org-element.el: Make affiliated keyword interpreter faster

* lisp/org-element.el (org-element--interpret-affiliated-keywords):
Optimize performance by bypassing unnecessary types and reducing
loop complexity.  Added new constant
`org-element-elements-no-affiliated' which stores the types to
be bypassed.

This function was doing redundant work on several levels which
dramatically reduced performance of interpreting element nodes
relative to object nodes.

First, all types were interpreted regardless of if they could
possibly contain affiliated keywords.  Skipping these types
dramatically speeds up typical use cases since many of these
skipped types are common (headline, item, etc).

Second, the loop was much more complex than needed.  It also
duplicated some work between calls to `org-element--properties-mapc'
and `mapconcat' (the code was moved entirely under
`org-element-properties-mapc').  The result should be faster and more
readable.
---
 lisp/org-element.el | 84 ++++++++++++++++++++++++---------------------
 1 file changed, 44 insertions(+), 40 deletions(-)

diff --git a/lisp/org-element.el b/lisp/org-element.el
index 56c03a0aa..3a199d26d 100644
--- a/lisp/org-element.el
+++ b/lisp/org-element.el
@@ -335,6 +335,12 @@ specially in `org-element--object-lex'.")
   (append org-element-recursive-objects '(paragraph table-row verse-block))
   "List of object or element types that can directly contain objects.")
 
+(defconst org-element-elements-no-affiliated
+  '(org-data comment clock headline inlinetask item
+             node-property planning property-drawer
+             section table-row)
+  "List of paragraph-level node types that cannot have affiliated keywords.")
+
 (defconst org-element-affiliated-keywords
   '("CAPTION" "DATA" "HEADER" "HEADERS" "LABEL" "NAME" "PLOT" "RESNAME" "RESULT"
     "RESULTS" "SOURCE" "SRCNAME" "TBLNAME")
@@ -5528,49 +5534,47 @@ to interpret.  Return Org syntax as a string."
 			      (make-string blank ?\n)))))))))
     (funcall fun data nil)))
 
+(defun org-element--interpret-affiliated-keyword (key value)
+  "Interpret affiliated keyword with KEY and VALUE."
+  (let (dual)
+    (when (member key org-element-dual-keywords)
+      (setq dual (cdr value) value (car value)))
+    (concat "#+" (downcase key)
+            (and dual
+                 (format "[%s]" (org-element-interpret-data dual)))
+            ": "
+            (if (member key org-element-parsed-keywords)
+                (org-element-interpret-data value)
+              value)
+            "\n")))
+
 (defun org-element--interpret-affiliated-keywords (element)
   "Return ELEMENT's affiliated keywords as Org syntax.
 If there is no affiliated keyword, return the empty string."
-  (let ((keyword-to-org
-	 (lambda (key value)
-	   (let (dual)
-	     (when (member key org-element-dual-keywords)
-	       (setq dual (cdr value) value (car value)))
-	     (concat "#+" (downcase key)
-		     (and dual
-			  (format "[%s]" (org-element-interpret-data dual)))
-		     ": "
-		     (if (member key org-element-parsed-keywords)
-			 (org-element-interpret-data value)
-		       value)
-		     "\n")))))
-    (mapconcat
-     (lambda (prop)
-       (let ((value (org-element-property prop element))
-	     (keyword (upcase (substring (symbol-name prop) 1))))
-	 (when value
-	   (if (or (member keyword org-element-multiple-keywords)
-		   ;; All attribute keywords can have multiple lines.
-		   (string-match-p "^ATTR_" keyword))
-	       (mapconcat (lambda (line) (funcall keyword-to-org keyword line))
-			  value "")
-	     (funcall keyword-to-org keyword value)))))
-     ;; List all ELEMENT's properties matching an attribute line or an
-     ;; affiliated keyword, but ignore translated keywords since they
-     ;; cannot belong to the property list.
-     (let (acc)
-       (org-element-properties-mapc
-        (lambda (prop _ __)
-          (let  ((keyword (upcase (substring (symbol-name prop) 1))))
-            (when (or (string-match-p "^ATTR_" keyword)
-		      (and
-		       (member keyword org-element-affiliated-keywords)
-		       (not (assoc keyword
-			         org-element-keyword-translation-alist))))
-              (push prop acc))))
-        element t)
-       (nreverse acc))
-     "")))
+  ;; there are some elements that will never have affiliated keywords,
+  ;; so do nothing for these
+  (if (member (org-element-type element)
+              org-element-elements-no-affiliated)
+      ""
+    (let (acc)
+      (org-element-properties-mapc
+       (lambda (prop value)
+         (when value
+           (let* ((keyword (upcase (substring (symbol-name prop) 1)))
+                  (attrp (string-match-p "^ATTR_" keyword)))
+             (when (or attrp
+                       (and
+                        (member keyword org-element-affiliated-keywords)
+                        (not (assoc keyword
+                                    org-element-keyword-translation-alist))))
+               (push (if (or attrp ; All attribute keywords can have multiple lines.
+                             (member keyword org-element-multiple-keywords))
+                         (mapconcat (lambda (line) (org-element--interpret-affiliated-keyword keyword line))
+                                    value "")
+                       (org-element--interpret-affiliated-keyword keyword value))
+                     acc)))))
+       element 'force)
+      (apply #'concat (nreverse acc)))))
 
 ;; Because interpretation of the parse tree must return the same
 ;; number of blank lines between elements and the same number of white
-- 
2.49.0

Reply via email to