gnucash stable: Multiple changes pushed

Christopher Lam clam at code.gnucash.org
Sat May 10 02:33:52 EDT 2025


Updated	 via  https://github.com/Gnucash/gnucash/commit/ff759c26 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/c01cccbd (commit)
	from  https://github.com/Gnucash/gnucash/commit/b219744d (commit)



commit ff759c26bcebef18f0327d3eef80a21d0d20e252
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Sun Apr 20 23:21:13 2025 +0800

    [engine.i] convert gnc_account_accumulate_at_dates to c++
    
    traversal of account->splits through std::vector instead of scm_list

diff --git a/bindings/engine.i b/bindings/engine.i
index 4b7adbafe7..bdc4d1abac 100644
--- a/bindings/engine.i
+++ b/bindings/engine.i
@@ -66,6 +66,22 @@ using AccountVec = std::vector<Account*>;
 SplitsVec gnc_get_match_commodity_splits (AccountVec accounts, bool use_end_date,
                                           time64 end_date, gnc_commodity *comm, bool sort);
 
+/* scans account splits, in posted date order, calling split_fn(split)
+   at each split and accumulate the result at each date in the SCM
+   list dates into a new SCM list. Parameters are:
+
+   acc            the account
+   dates          the SCM list of posted dates, assumed to be in chronological order
+   init           the result to be pushed into the result for dates prior to first split date
+   split_fn       the split->elt procedure whose result of (split_fn split) will be pushed
+                  into the returned SCM list */
+SCM gnc_account_accumulate_to_dates (const Account *acc, SCM dates,
+                                     SCM split_fn, SCM init);
+
+/* as above, but the split_to_date function to use a different date order. */
+SCM gnc_account_accumulate_to_dates (const Account *acc, SCM dates,
+                                     SCM split_fn, SCM init, SCM split_to_date);
+
 AccountVec gnc_accounts_and_all_descendants (AccountVec accounts);
 
 extern "C"
@@ -160,6 +176,51 @@ SplitsVec gnc_get_match_commodity_splits (AccountVec accounts, bool use_end_date
     return rv;
 }
 
+static SCM
+accumulate_splits_by_dates (const SplitsVec& splits, SCM dates, SCM result,
+                            std::function<bool(Split*,SCM)> no_later_than_date,
+                            std::function<SCM(Split*)> get_result)
+{
+    SCM rv = SCM_EOL;
+    auto splits_it = splits.begin();
+    for (; !scm_is_null(dates); dates = scm_cdr (dates))
+    {
+        while (splits_it != splits.end() && no_later_than_date (*splits_it, scm_car (dates)))
+            result = get_result (*splits_it++);
+
+        rv = scm_cons (result, rv);
+    }
+    return scm_reverse_x (rv, SCM_EOL);
+}
+
+SCM
+gnc_account_accumulate_to_dates (const Account *acc, SCM dates,
+                                 SCM split_fn, SCM init)
+{
+    const auto& splits = xaccAccountGetSplits(acc);
+    auto get_result = [&](Split* s) -> SCM { return scm_call_1(split_fn, gnc_split_to_scm(s)); };
+    auto no_later_than_date = [&](Split* s, SCM date) -> bool
+        { return xaccTransGetDate (xaccSplitGetParent (s)) <= scm_to_int64 (date); };
+
+    return accumulate_splits_by_dates (splits, dates, init, no_later_than_date, get_result);
+}
+
+SCM
+gnc_account_accumulate_to_dates (const Account *acc, SCM dates,
+                                 SCM split_fn, SCM init, SCM split_to_date)
+{
+    auto splits = xaccAccountGetSplits(acc);
+    auto less_scm = [](SCM a, SCM b) -> bool { return scm_is_true(scm_less_p(a, b)); };
+    auto get_date = [&](Split* s) -> SCM { return scm_call_1(split_to_date, gnc_split_to_scm(s)); };
+    auto get_result = [&](Split* s) -> SCM { return scm_call_1(split_fn, gnc_split_to_scm(s)); };
+    auto no_later_than_date = [&](auto s, SCM date) -> bool { return !less_scm(date, get_date(s)); };
+    std::sort(splits.begin(), splits.end(), [&](auto a, auto b) -> bool
+              { return less_scm(get_date(a), get_date(b)); });
+
+    return accumulate_splits_by_dates (splits, dates, init, no_later_than_date, get_result);
+}
+
+
 using AccountSet = std::unordered_set<Account*>;
 static void maybe_add_descendants (Account* acc, AccountSet* accset)
 {
diff --git a/gnucash/report/report-utilities.scm b/gnucash/report/report-utilities.scm
index a1b90ff5e5..7a39221f59 100644
--- a/gnucash/report/report-utilities.scm
+++ b/gnucash/report/report-utilities.scm
@@ -476,41 +476,9 @@
           (nosplit->elt #f)
           (split->date #f)
           (split->elt xaccSplitGetBalance))
-  (define to-date (or split->date (compose xaccTransGetDate xaccSplitGetParent)))
-  (define (less? a b) (< (to-date a) (to-date b)))
-
-  (let lp ((splits (if split->date
-                       (sort (xaccAccountGetSplits acc) less?)
-                       (xaccAccountGetSplits acc)))
-           (dates (sort dates <))
-           (result '())
-           (last-result nosplit->elt))
-    (match dates
-
-      ;; end of dates. job done!
-      (() (reverse result))
-
-      ((date . rest)
-       (define (before-date? s) (<= (to-date s) date))
-       (define (after-date? s) (< date (to-date s)))
-       (cond
-
-        ;; end of splits, but still has dates. pad with last-result
-        ;; until end of dates.
-        ((null? splits) (lp '() rest (cons last-result result) last-result))
-
-        ;; the next split is still before date.
-        ((and (pair? (cdr splits)) (before-date? (cadr splits)))
-         (lp (cdr splits) dates result (split->elt (car splits))))
-
-        ;; head split after date, accumulate previous result
-        ((after-date? (car splits))
-         (lp splits rest (cons last-result result) last-result))
-
-        ;; head split before date, next split after date, or end.
-        (else
-         (let ((head-result (split->elt (car splits))))
-           (lp (cdr splits) rest (cons head-result result) head-result))))))))
+  (if split->date
+      (gnc-account-accumulate-to-dates acc dates split->elt nosplit->elt split->date)
+      (gnc-account-accumulate-to-dates acc dates split->elt nosplit->elt)))
 
 ;; This works similar as above but returns a commodity-collector,
 ;; thus takes care of children accounts with different currencies.

commit c01cccbddc6049632ccfcc254c32cc419e3b40fb
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Sun Apr 20 23:20:54 2025 +0800

    [gnc-engine-guile.cpp] helper gnc_split_to_scm function

diff --git a/bindings/guile/gnc-engine-guile.cpp b/bindings/guile/gnc-engine-guile.cpp
index fd6426d1bc..2c3f5be575 100644
--- a/bindings/guile/gnc-engine-guile.cpp
+++ b/bindings/guile/gnc-engine-guile.cpp
@@ -1781,6 +1781,13 @@ gnc_book_to_scm (const QofBook *book)
     return gnc_generic_to_scm (book, stype);
 }
 
+SCM
+gnc_split_to_scm (const Split *split)
+{
+    static auto stype = get_swig_type ("_p_Split");
+    return gnc_generic_to_scm (split, stype);
+}
+
 GncAccountValue * gnc_scm_to_account_value_ptr (SCM valuearg)
 {
     GncAccountValue *res;
diff --git a/bindings/guile/gnc-engine-guile.h b/bindings/guile/gnc-engine-guile.h
index 2795e8e287..07687928d6 100644
--- a/bindings/guile/gnc-engine-guile.h
+++ b/bindings/guile/gnc-engine-guile.h
@@ -66,6 +66,8 @@ SCM gnc_commodity_to_scm(const gnc_commodity* commodity);
 
 SCM gnc_book_to_scm(const QofBook* book);
 
+SCM gnc_split_to_scm (const Split *split);
+
 /* Conversion routines used with tax tables */
 GncAccountValue* gnc_scm_to_account_value_ptr(SCM valuearg);
 



Summary of changes:
 bindings/engine.i                   | 61 +++++++++++++++++++++++++++++++++++++
 bindings/guile/gnc-engine-guile.cpp |  7 +++++
 bindings/guile/gnc-engine-guile.h   |  2 ++
 gnucash/report/report-utilities.scm | 38 ++---------------------
 4 files changed, 73 insertions(+), 35 deletions(-)



More information about the gnucash-changes mailing list