(perf)utils: optimize org-roam-plist-map! (#1958)

The old implementation:

- did not handle duplicate keys well (the function would be applied to each value, but only the first value would be updated with the last value's result)
- was quadratic in the length of the input list (for each key, plist-put would search for the first occurrence of the key by going through all previous elements again)
- copied the input sequence even though this was not really needed
- did not provide a result value that could be useful, thus encouraging imperative programming
- did not need to be a macro, and the macro implementation was evaluating fn multiple times and causing warnings in the native compiler because k and v were not bound.
This commit is contained in:
Philippe Crama
2021-11-11 12:59:36 +01:00
committed by GitHub
parent 25bc3acce3
commit 721f167563

View File

@ -60,17 +60,15 @@ Like `string-equal', but case-insensitive."
(string-equal (downcase s1) (downcase s2))))) (string-equal (downcase s1) (downcase s2)))))
;;; List utilities ;;; List utilities
(defmacro org-roam-plist-map! (fn plist) (defun org-roam-plist-map! (fn plist)
"Map FN over PLIST, modifying it in-place." "Map FN over PLIST, modifying it in-place and returning it.
(declare (indent 1)) FN must take two arguments: the key and the value."
(let ((plist-var (make-symbol "plist")) (let ((plist-index plist))
(k (make-symbol "k")) (while plist-index
(v (make-symbol "v"))) (let ((key (pop plist-index)))
`(let ((,plist-var (copy-sequence ,plist))) (setf (car plist-index) (funcall fn key (car plist-index))
(while ,plist-var plist-index (cdr plist-index)))))
(setq ,k (pop ,plist-var)) plist)
(setq ,v (pop ,plist-var))
(setq ,plist (plist-put ,plist ,k (funcall ,fn ,k ,v)))))))
;;; File utilities ;;; File utilities
(defmacro org-roam-with-file (file keep-buf-p &rest body) (defmacro org-roam-with-file (file keep-buf-p &rest body)