Hi,

The attached patch simplifies the column summary computation in
`org-columns--compute-spec' by replacing the dynamically resized vector
and level-clearing loops with a stack of (level . value) pairs.
                                                                                
                                                               
This refactoring:                                                               
                                                           
1. Significantly simplifies the code and improves readability by                
                                                           
   removing three auxiliary functions (`org-columns--extend-values-by-level',   
                                                           
   `org-columns--values-below-level', and 
`org-columns--clear-values-below-level'), manual vector resizing, and           
                                                        
   nested loops.                                                                
                                                           
2. Eliminates the overhead of iterating over deeper levels when                 
                                                           
   ascending the outline tree.                                                  
                                                           
3. Yields significant performance improvements on hierarchical structures,      
                                                           
   scaling up to 5x–10x speedup on deep trees.                                  
                                                           
                                                                       
Benchmark (10 runs each, median times for summary computation):                 
                                                           

5 summary columns (depth 5):
   Headings  Depth   Old (vector)   New (stack)   Speedup
   ──────────────────────────────────────────────────────
         10      5      0.00490 s     0.00214 s     2.3×
        100      5      0.04935 s     0.01607 s     3.1×
        500      5      0.25625 s     0.13464 s     1.9×
       1000      5      0.56025 s     0.26654 s     2.1×
       2000      5      1.14261 s     0.74478 s     1.5×

10 summary columns (deep hierarchy, depth 10):
   Headings  Depth   Old (vector)   New (stack)   Speedup
   ──────────────────────────────────────────────────────
        100     10      0.26293 s     0.02592 s    10.1×
        500     10      0.77635 s     0.15476 s     5.0×
       1000     10      1.14439 s     0.23697 s     4.8×
       2000     10      2.37339 s     0.47034 s     5.0×

Scaling across hierarchy depth (1000 headings, 5 summary columns):
   Headings  Depth   Old (vector)   New (stack)   Speedup
   ──────────────────────────────────────────────────────
       1000      4      0.55512 s     0.30566 s     1.8×
       1000      8      1.06393 s     0.22224 s     4.8×
       1000     16      0.57331 s     0.09688 s     5.9×
       1000     30      0.63103 s     0.09008 s     7.0×

Best,
-- 
Slawomir Grochowski
From f533d77b4bad34c1c142b562cd5552458d657a81 Mon Sep 17 00:00:00 2001
From: Slawomir Grochowski <[email protected]>
Date: Thu, 20 Aug 2026 15:10:54 +0200
Subject: [PATCH] ; org-colview: Simplify column summary computation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* lisp/org-colview.el (org-columns--extend-values-by-level)
(org-columns--values-below-level)
(org-columns--clear-values-below-level): Remove.
(org-columns--compute-spec): Use a stack of level-value pairs instead of
a dynamically resized vector and level-clearing loops.

Using a stack significantly simplifies the code and improves readability
by eliminating three auxiliary helper functions, manual vector resizing,
and nested level-clearing loops.

It also eliminates the overhead of iterating over deeper levels when
ascending the outline tree.  The speedup scales with the depth of the
hierarchy (up to 5×–10× on deep trees):

Benchmark (10 runs each, median times for summary computation)

  5 summary columns (depth 5):
     Headings  Depth   Old (vector)   New (stack)   Speedup
     ──────────────────────────────────────────────────────
           10      5      0.00490 s     0.00214 s     2.3×
          100      5      0.04935 s     0.01607 s     3.1×
          500      5      0.25625 s     0.13464 s     1.9×
         1000      5      0.56025 s     0.26654 s     2.1×
         2000      5      1.14261 s     0.74478 s     1.5×

  10 summary columns (deep hierarchy, depth 10):
     Headings  Depth   Old (vector)   New (stack)   Speedup
     ──────────────────────────────────────────────────────
          100     10      0.26293 s     0.02592 s    10.1×
          500     10      0.77635 s     0.15476 s     5.0×
         1000     10      1.14439 s     0.23697 s     4.8×
         2000     10      2.37339 s     0.47034 s     5.0×

  Scaling across hierarchy depth (1000 headings, 5 summary columns):
     Headings  Depth   Old (vector)   New (stack)   Speedup
     ──────────────────────────────────────────────────────
         1000      4      0.55512 s     0.30566 s     1.8×
         1000      8      1.06393 s     0.22224 s     4.8×
         1000     16      0.57331 s     0.09688 s     5.9×
         1000     30      0.63103 s     0.09008 s     7.0×

Refactoring: Inline Function, Consolidate Conditional Expression.

No behavior change.
---
 lisp/org-colview.el | 79 ++++++++++++++-------------------------------
 1 file changed, 24 insertions(+), 55 deletions(-)

diff --git a/lisp/org-colview.el b/lisp/org-colview.el
index d5548802f..ee4cf9793 100644
--- a/lisp/org-colview.el
+++ b/lisp/org-colview.el
@@ -1549,35 +1549,17 @@ they have their own way to be computed."
     (and (not (member property org-special-properties))
 	 (org-columns--spec-operator spec))))
 
-(defun org-columns--extend-values-by-level (values-by-level level)
-  "Return VALUES-BY-LEVEL large enough to include LEVEL."
-  (if (< level (length values-by-level)) values-by-level
-    (vconcat values-by-level
-             (make-vector (- (1+ level) (length values-by-level)) nil))))
-
-(defun org-columns--values-below-level (values-by-level level)
-  "Return values in VALUES-BY-LEVEL accumulated deeper than LEVEL."
-  (cl-loop for deeper-level from (1+ level) below (length values-by-level)
-	   append (aref values-by-level deeper-level)))
-
-(defun org-columns--clear-values-below-level (values-by-level level)
-  "Clear accumulated values below LEVEL in VALUES-BY-LEVEL."
-  (cl-loop for deeper-level from (1+ level) below (length values-by-level)
-	   do (aset values-by-level deeper-level nil)))
-
 (defun org-columns--compute-spec (spec &optional update-property-p)
   "Update tree according to SPEC.
 SPEC is a column format specification.  When optional argument
 UPDATE-PROPERTY-P is non-nil, summarized values can replace
 existing ones in properties drawers."
   (when-let* ((operator (org-columns--summarizable-operator spec)))
-    (let* ((values-by-level (make-vector 1 nil))
-	   (current-level 0)
-	   (previous-level 0)
-	   (property (org-columns--spec-property spec))
-	   (format-string (org-columns--spec-format-string spec))
-	   (collect-function (org-columns--collect-function operator))
-	   (summarize-function (org-columns--summarize-function operator)))
+    (let ((property (org-columns--spec-property spec))
+	  (format-string (org-columns--spec-format-string spec))
+	  (collect-function (org-columns--collect-function operator))
+	  (summarize-function (org-columns--summarize-function operator))
+	  (stack nil))
       (org-with-wide-buffer
        ;; Find the region to compute.
        (goto-char org-columns-top-level-marker)
@@ -1585,38 +1567,25 @@ existing ones in properties drawers."
        ;; Walk the tree from the back and do the computations.
        (while (re-search-backward
 	       org-outline-regexp-bol org-columns-top-level-marker t)
-	 (unless (= current-level 0) (setq previous-level current-level))
-	 (setq current-level (org-reduced-level (org-outline-level)))
-	 (setq values-by-level
-	       (org-columns--extend-values-by-level
-		values-by-level current-level))
-	 (let* ((pos (match-beginning 0))
-		(current-value (if collect-function
-				   (funcall collect-function property)
-				 (org-entry-get (point) property)))
-		(value-nonempty-p (org-string-nw-p current-value)))
-	   (cond
-	    ((< current-level previous-level)
-	     ;; Collect values from lower levels and inline tasks here
-	     ;; and summarize them using SUMMARIZE-FUNCTION.  Store them in text
-	     ;; property `org-summaries', in alist whose key is SPEC.
-	     (let* ((values (and summarize-function
-				 (org-columns--values-below-level
-				  values-by-level current-level)))
-		    (summary (and values
-				  (funcall summarize-function values format-string))))
-	       (cond
-		(summary
-		 (org-columns--put-summary pos spec summary)
-		 (when update-property-p
-		   (org-columns--update-summary-property property current-value summary))
-		 (push summary (aref values-by-level current-level)))
-		(value-nonempty-p
-		 (push current-value (aref values-by-level current-level))))
-	       (org-columns--clear-values-below-level
-		values-by-level current-level)))
-	    (value-nonempty-p
-	     (push current-value (aref values-by-level current-level))))))))))
+	 (let* ((level (org-reduced-level (org-outline-level)))
+		(child-values nil))
+	   (while (and stack (< level (caar stack)))
+	     (push (cdr (pop stack)) child-values))
+	   (setq child-values (nreverse child-values))
+	   (let* ((summary (and summarize-function
+				child-values
+				(funcall summarize-function child-values format-string)))
+		  (current-value (and (or update-property-p (not summary))
+				      (if collect-function
+					  (funcall collect-function property)
+					(org-entry-get (point) property))))
+		  (value (cond
+			  (summary (org-columns--put-summary (point) spec summary)
+			   (when update-property-p (org-columns--update-summary-property property current-value summary))
+			   summary)
+			  (t current-value))))
+	     (when (org-string-nw-p value)
+	       (push (cons level value) stack)))))))))
 
 ;;;###autoload
 (defun org-columns-compute (property)
-- 
2.39.5

Reply via email to