gnucash stable: Multiple changes pushed

Christopher Lam clam at code.gnucash.org
Mon Apr 22 07:36:13 EDT 2024


Updated	 via  https://github.com/Gnucash/gnucash/commit/5dab612d (commit)
	 via  https://github.com/Gnucash/gnucash/commit/3dc0df7f (commit)
	 via  https://github.com/Gnucash/gnucash/commit/daadfcf4 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/0bd0f777 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/a993e972 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/68f60fef (commit)
	 via  https://github.com/Gnucash/gnucash/commit/cb7196a3 (commit)
	from  https://github.com/Gnucash/gnucash/commit/80f82e9d (commit)



commit 5dab612d1b03c58f45ebcf3ccdc770d8b8ecccd1
Merge: 80f82e9d47 3dc0df7f38
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Mon Apr 22 19:34:19 2024 +0800

    Merge branch 'bug799258-cpp' into stable #1920


commit 3dc0df7f383d1b839b1d0534de24922bbd3836c7
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Sun Apr 21 14:00:49 2024 +0800

    [commodity-utilities.scm] routines upgraded to accept a #:hide-warnings? argument
    
    ... whose default is #f, therefore warnings are shown.
    
    In gnc:case-exchange-time-fn the routines are called at the report
    end-date once. Therefore all relevant splits are analysed for
    warnings.
    
    Subsequent calls (at various report dates) will omit warnings.

diff --git a/gnucash/report/commodity-utilities.scm b/gnucash/report/commodity-utilities.scm
index 836be3151e..5e66551175 100644
--- a/gnucash/report/commodity-utilities.scm
+++ b/gnucash/report/commodity-utilities.scm
@@ -124,10 +124,12 @@
   (gnc:get-commodity-totalavg-prices-internal
    currency-accounts end-date price-commodity report-currency
    (gnc:get-match-commodity-splits-sorted
-    currency-accounts end-date price-commodity)))
+    currency-accounts end-date price-commodity)
+   #f))
 
 (define (gnc:get-commodity-totalavg-prices-internal
-         currency-accounts end-date price-commodity report-currency commodity-splits)
+         currency-accounts end-date price-commodity report-currency commodity-splits
+         hide-warnings?)
   (let loop ((tot-foreign 0)
              (tot-domestic 0)
              (commodity-splits commodity-splits)
@@ -173,16 +175,17 @@
                          (cons (list txn-date (/ new-domestic new-foreign)) result)))))
 
            (else
-            (warn "gnc:get-commodity-totalavg-prices: "
-                  "Sorry, currency exchange not yet implemented:"
-                  (gnc:monetary->string
-                   (gnc:make-gnc-monetary txn-comm value-amt))
-                  " (buying "
-                  (gnc:monetary->string
-                   (gnc:make-gnc-monetary price-commodity share-amt))
-                  ") =? "
-                  (gnc:monetary->string
-                   (gnc:make-gnc-monetary report-currency 0)))
+            (unless hide-warnings?
+              (warn "gnc:get-commodity-totalavg-prices: "
+                    "Sorry, currency exchange not yet implemented:"
+                    (gnc:monetary->string
+                     (gnc:make-gnc-monetary txn-comm value-amt))
+                    " (buying "
+                    (gnc:monetary->string
+                     (gnc:make-gnc-monetary price-commodity share-amt))
+                    ") =? "
+                    (gnc:monetary->string
+                     (gnc:make-gnc-monetary report-currency 0))))
             (loop tot-foreign
                   tot-domestic
                   (cdr commodity-splits)
@@ -194,9 +197,9 @@
 ;; extended to a commodity-list. Returns an alist. Each pair consists
 ;; of the foreign-currency and the appropriate list from
 ;; gnc:get-commodity-totalavg-prices, see there.
-(define (gnc:get-commoditylist-totalavg-prices
-         commodity-list report-currency end-date
-         start-percent delta-percent)
+(define* (gnc:get-commoditylist-totalavg-prices
+          commodity-list report-currency end-date
+          start-percent delta-percent #:key hide-warnings?)
   (let* ((currency-accounts
           (gnc-account-get-descendants-sorted (gnc-get-current-root-account)))
          (interesting-splits (gnc:get-match-commodity-splits-sorted currency-accounts end-date #f))
@@ -213,7 +216,8 @@
        (cons c
              (gnc:get-commodity-totalavg-prices-internal
               currency-accounts end-date c report-currency
-              (filter split-has-commodity? interesting-splits))))
+              (filter split-has-commodity? interesting-splits)
+              hide-warnings?)))
      commodity-list
      (iota work-to-do))))
 
@@ -306,7 +310,7 @@
 ;; (described in gnc:get-exchange-totals) and returns a report-list, This
 ;; resulting alist can immediately be plugged into gnc:make-exchange-alist.
 
-(define (gnc:resolve-unknown-comm sumlist report-commodity)
+(define* (gnc:resolve-unknown-comm sumlist report-commodity #:key hide-warnings?)
   ;; reportlist contains all known transactions with the
   ;; report-commodity, and now the transactions with unknown
   ;; currencies should be added to that list (with an appropriate
@@ -381,28 +385,30 @@
               ;; If neither the currency of (car sumlist) nor of pair
               ;; was found in reportlist then we can't resolve the
               ;; exchange rate to this currency.
-              (warn "gnc:resolve-unknown-comm:"
-                    "can't calculate rate for "
-                    (gnc:monetary->string
-                     (gnc:make-gnc-monetary (car pair) ((caadr pair) 'total #f)))
-                    " = "
-                    (gnc:monetary->string
-                     (gnc:make-gnc-monetary (caar sumlist) ((cdadr pair) 'total #f)))
-                    " to "
-                    (gnc:monetary->string (gnc:make-gnc-monetary report-commodity 0)))
+              (unless hide-warnings?
+                (warn "gnc:resolve-unknown-comm:"
+                      "can't calculate rate for "
+                      (gnc:monetary->string
+                       (gnc:make-gnc-monetary (car pair) ((caadr pair) 'total #f)))
+                      " = "
+                      (gnc:monetary->string
+                       (gnc:make-gnc-monetary (caar sumlist) ((cdadr pair) 'total #f)))
+                      " to "
+                      (gnc:monetary->string (gnc:make-gnc-monetary report-commodity 0))))
               (innerloop (cdr pairs) reportlist))
 
              ((and pair-a pair-b)
               ;; If both currencies are found then something went
               ;; wrong inside gnc:get-exchange-totals. FIXME: Find a
               ;; better thing to do in this case.
-              (warn "gnc:resolve-unknown-comm:"
-                    "Oops - exchange rate ambiguity error: "
-                    (gnc:monetary->string
-                     (gnc:make-gnc-monetary (car pair) ((caadr pair) 'total #f)))
-                    " = "
-                    (gnc:monetary->string
-                     (gnc:make-gnc-monetary (caar sumlist) ((cdadr pair) 'total #f))))
+              (unless hide-warnings?
+                (warn "gnc:resolve-unknown-comm:"
+                      "Oops - exchange rate ambiguity error: "
+                      (gnc:monetary->string
+                       (gnc:make-gnc-monetary (car pair) ((caadr pair) 'total #f)))
+                      " = "
+                      (gnc:monetary->string
+                       (gnc:make-gnc-monetary (caar sumlist) ((cdadr pair) 'total #f)))))
               (innerloop (cdr pairs) reportlist))
 
              ;; Usual case: one of pair-{a,b} was found in reportlist,
@@ -511,7 +517,7 @@
 ;; Sum the net amounts and values in the report commodity, including booked
 ;; gains and losses, of each commodity across all accounts. Returns a
 ;; report-list.
-(define (gnc:get-exchange-cost-totals report-commodity end-date)
+(define* (gnc:get-exchange-cost-totals report-commodity end-date #:key hide-warnings?)
   (let ((curr-accounts (gnc-account-get-descendants-sorted
                         (gnc-get-current-root-account))))
 
@@ -519,7 +525,7 @@
                (sumlist (list (list report-commodity '()))))
       (cond
        ((null? comm-splits)
-        (gnc:resolve-unknown-comm sumlist report-commodity))
+        (gnc:resolve-unknown-comm sumlist report-commodity #:hide-warnings? hide-warnings?))
 
        ;; However skip splits in trading accounts as these counterbalance
        ;; the actual value and share amounts back to zero
@@ -600,7 +606,7 @@
       (list comm (abs (/ (foreign 'total #f) (domestic 'total #f))))))
    (gnc:get-exchange-totals report-commodity end-date)))
 
-(define (gnc:make-exchange-cost-alist report-commodity end-date)
+(define* (gnc:make-exchange-cost-alist report-commodity end-date #:key hide-warnings?)
   ;; This returns the alist with the actual exchange rates, i.e. the
   ;; total balances from get-exchange-totals are divided by each
   ;; other.
@@ -609,7 +615,7 @@
      ((comm (domestic . foreign))
       (let ((denom (domestic 'total #f)))
         (list comm (if (zero? denom) 0 (abs (/ (foreign 'total #f) denom)))))))
-   (gnc:get-exchange-cost-totals report-commodity end-date)))
+   (gnc:get-exchange-cost-totals report-commodity end-date #:hide-warnings? hide-warnings?)))
 
 
 
@@ -826,6 +832,18 @@
   (define date-hash (make-hash-table))
   (define-syntax-rule (memoize date expensive-fn)
     (or (hash-ref date-hash date) (hashv-set! date-hash date expensive-fn)))
+  ;; call the expensive function ONCE with the warnings enabled. this
+  ;; will log any warnings related to impossible currency conversions
+  ;; for splits upto the report-date
+  (case source-option
+    ((average-cost) (memoize to-date-tp
+                             (gnc:make-exchange-function
+                              (gnc:make-exchange-cost-alist
+                               report-currency to-date-tp))))
+    ((weighted-average) (memoize to-date-tp
+                                 (gnc:get-commoditylist-totalavg-prices
+                                  commodity-list report-currency to-date-tp
+                                  start-percent delta-percent))))
   (case source-option
     ;; Make this the same as gnc:case-exchange-fn
     ((average-cost) (lambda (foreign domestic date)
@@ -833,14 +851,16 @@
                              (exchange-fn (memoize end-day
                                                    (gnc:make-exchange-function
                                                     (gnc:make-exchange-cost-alist
-                                                     report-currency end-day)))))
+                                                     report-currency end-day
+                                                      #:hide-warnings? #t)))))
                         (exchange-fn foreign domestic))))
     ((weighted-average) (lambda (foreign domestic date)
                           (let* ((end-day (gnc:time64-end-day-time date))
                                  (pricealist (memoize end-day
                                                       (gnc:get-commoditylist-totalavg-prices
                                                        commodity-list report-currency end-day
-                                                       start-percent delta-percent))))
+                                                       start-percent delta-percent
+                                                        #:hide-warnings? #t))))
                             (gnc:exchange-by-pricealist-nearest
                              pricealist foreign domestic date))))
     ((pricedb-before) gnc:exchange-by-pricedb-nearest-before)

commit daadfcf426510d2c30c04fb88f010aadda7d3b22
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Sat Apr 20 19:38:31 2024 +0800

    [balsheet-pnl.scm] use enhanced gnc:case-exchange-time-fn
    
    Because gnc:case-exchange-time-fn now handles multiple report dates
    correctly.

diff --git a/gnucash/report/reports/standard/balsheet-pnl.scm b/gnucash/report/reports/standard/balsheet-pnl.scm
index 2c678c83e4..da80ad300e 100644
--- a/gnucash/report/reports/standard/balsheet-pnl.scm
+++ b/gnucash/report/reports/standard/balsheet-pnl.scm
@@ -736,17 +736,10 @@ also show overall period profit & loss."))
               (cons acc (map col-datum-get-split-balance-with-closing cols-data))))
            accounts-cols-data))
 
-         ;; generate an exchange-fn for date, and cache its result.
-         (get-date-exchange-fn
-          (let ((h (make-hash-table))
-                (commodities (gnc:accounts-get-commodities accounts #f)))
-            (lambda (date)
-              (or (hashv-ref h date)
-                  (let ((exchangefn (gnc:case-exchange-time-fn
-                                     price-source common-currency commodities
-                                     date #f #f)))
-                    (hashv-set! h date exchangefn)
-                    exchangefn)))))
+         ;; generate an exchange-fn
+         (exchange-fn (gnc:case-exchange-time-fn price-source common-currency
+                                                 (gnc:accounts-get-commodities accounts #f)
+                                                 #f #f #f))
 
          ;; from col-idx, find effective date to retrieve pricedb
          ;; entry or to limit transactions to calculate average-cost
@@ -772,8 +765,7 @@ also show overall period profit & loss."))
                        (gnc:gnc-monetary-commodity monetary)
                        common-currency))
                  (has-price? (gnc:gnc-monetary-commodity monetary))
-                 (let* ((col-date (col-idx->price-date col-idx))
-                        (exchange-fn (get-date-exchange-fn col-date)))
+                 (let ((col-date (col-idx->price-date col-idx)))
                    (exchange-fn monetary common-currency col-date)))))
 
          ;; the following function generates an gnc:html-text object

commit 0bd0f777428c5eaf0d0c4e81ce0190edd4b70174
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Thu Apr 18 21:30:38 2024 +0800

    Bug 799258 - Reports calculating net worth incorrectly after stock split
    
    For average-cost and weighted-average: when the exchange-fn is
    created, it would formerly consider the whole book foreign currency
    conversions to calculate the date-specific conversions. This bug fix
    will limit the book conversions to those earlier than the
    date-specific conversions.
    
    The book retrieval functions are expensive, therefore the analysis
    splitlists are cached in the date-hash hash-table, which is scoped
    within the exchange-fn lambda only, and is garbage collected when
    exchange-fn is out of scope.
    
    Also: amend relevant commodity-utilities.scm tests
    
    The old weighted-average and average-cost tests were written to
    document the (knowingly) incorrect exchanged amounts as originally
    calculated pre-2024.
    
    In 2024, the exchange-fn is fixed so that foreign currency
    conversions at a particular report date would consider only
    transactions up to the relevant report date.
    
    The first AAPL transaction in this test book is on 09/08/2013: a
    purchase of 600 AAPL at $36840 total @ $61.40 each.
    
    Therefore the first test, on 20/02/2012 the AAPL->USD exchange rate
    conversion should be zero, since there are no AAPL transactions
    yet.
    
    Subsequent AAPL test on 20/02/2014 shows the conversion of 1
    AAPL to be 307/5 which matches $61.40.
    
    etc.

diff --git a/gnucash/report/commodity-utilities.scm b/gnucash/report/commodity-utilities.scm
index ffb8cacdc6..836be3151e 100644
--- a/gnucash/report/commodity-utilities.scm
+++ b/gnucash/report/commodity-utilities.scm
@@ -823,19 +823,24 @@
 (define (gnc:case-exchange-time-fn
          source-option report-currency commodity-list to-date-tp
          start-percent delta-percent)
+  (define date-hash (make-hash-table))
+  (define-syntax-rule (memoize date expensive-fn)
+    (or (hash-ref date-hash date) (hashv-set! date-hash date expensive-fn)))
   (case source-option
     ;; Make this the same as gnc:case-exchange-fn
-    ((average-cost) (let* ((exchange-fn (gnc:make-exchange-function
-                                         (gnc:make-exchange-cost-alist
-                                          report-currency to-date-tp))))
-                      (lambda (foreign domestic date)
+    ((average-cost) (lambda (foreign domestic date)
+                      (let* ((end-day (gnc:time64-end-day-time date))
+                             (exchange-fn (memoize end-day
+                                                   (gnc:make-exchange-function
+                                                    (gnc:make-exchange-cost-alist
+                                                     report-currency end-day)))))
                         (exchange-fn foreign domestic))))
-    ((weighted-average) (let ((pricealist
-                               (gnc:get-commoditylist-totalavg-prices
-                                commodity-list report-currency to-date-tp
-                                start-percent delta-percent)))
-                          (gnc:debug "weighted-average pricealist " pricealist)
-                          (lambda (foreign domestic date)
+    ((weighted-average) (lambda (foreign domestic date)
+                          (let* ((end-day (gnc:time64-end-day-time date))
+                                 (pricealist (memoize end-day
+                                                      (gnc:get-commoditylist-totalavg-prices
+                                                       commodity-list report-currency end-day
+                                                       start-percent delta-percent))))
                             (gnc:exchange-by-pricealist-nearest
                              pricealist foreign domestic date))))
     ((pricedb-before) gnc:exchange-by-pricedb-nearest-before)
diff --git a/gnucash/report/test/test-commodity-utils.scm b/gnucash/report/test/test-commodity-utils.scm
index 11166f3cfe..da634051df 100644
--- a/gnucash/report/test/test-commodity-utils.scm
+++ b/gnucash/report/test/test-commodity-utils.scm
@@ -655,7 +655,7 @@
                           (gnc-dmy2time64-neutral 20 02 2016)
                           #f #f)))
         (test-equal "gnc:case-exchange-time-fn weighted-average 20/02/2012"
-          307/5
+          0
           (gnc:gnc-monetary-amount
            (exchange-fn
             (gnc:make-gnc-monetary AAPL 1)
@@ -663,7 +663,7 @@
             (gnc-dmy2time64-neutral 20 02 2012))))
 
         (test-equal "gnc:case-exchange-time-fn weighted-average 20/02/2014"
-          9366/125
+          307/5
           (gnc:gnc-monetary-amount
            (exchange-fn
             (gnc:make-gnc-monetary AAPL 1)
@@ -687,7 +687,7 @@
             (gnc-dmy2time64-neutral 11 08 2014))))
 
         (test-equal "gnc:case-exchange-time-fn weighted-average 22/10/2015"
-          27663/325
+          9366/125
           (gnc:gnc-monetary-amount
            (exchange-fn
             (gnc:make-gnc-monetary AAPL 1)
@@ -708,7 +708,7 @@
                           (gnc-dmy2time64-neutral 20 02 2016)
                           #f #f)))
         (test-equal "gnc:case-exchange-time-fn average-cost 20/02/2012"
-          14127/175
+          0
           (gnc:gnc-monetary-amount
            (exchange-fn
             (gnc:make-gnc-monetary AAPL 1)

commit a993e97204ebd342b4b102e90d801b66016c2667
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Thu Apr 18 00:19:28 2024 +0800

    [commodity-utilities.scm] use gnc_get_match_commodity_splits

diff --git a/gnucash/report/commodity-utilities.scm b/gnucash/report/commodity-utilities.scm
index a91b8ba9e5..ffb8cacdc6 100644
--- a/gnucash/report/commodity-utilities.scm
+++ b/gnucash/report/commodity-utilities.scm
@@ -61,18 +61,10 @@
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Functions to get splits with interesting data from accounts.
 
-;; helper function. queries book for all splits in accounts before
-;; end-date (end-date can be #f)
-(define (get-all-splits accounts end-date)
-  (let ((query (qof-query-create-for-splits)))
-    (qof-query-set-book query (gnc-get-current-book))
-    (xaccQueryAddClearedMatch
-     query (logand CLEARED-ALL (lognot CLEARED-VOIDED)) QOF-QUERY-AND)
-    (xaccQueryAddAccountMatch query accounts QOF-GUID-MATCH-ANY QOF-QUERY-AND)
-    (xaccQueryAddDateMatchTT query #f 0 (and end-date #t) (or end-date 0) QOF-QUERY-AND)
-    (let ((splits (qof-query-run query)))
-      (qof-query-destroy query)
-      splits)))
+(define (get-all-commodity-splits currency-accounts end-date commodity sort?)
+  (gnc-get-match-commodity-splits currency-accounts (and end-date #t)
+                                  (or end-date 0) (or commodity '()) sort?))
+
 
 ;; Returns a list of all splits in the 'currency-accounts' up to
 ;; 'end-date' which have two different commodities involved, one of
@@ -80,15 +72,7 @@
 ;; 'commodity' != #f ).
 (define (gnc:get-match-commodity-splits
          currency-accounts end-date commodity)
-  (filter
-   (lambda (s)
-     (let ((txn-comm (xaccTransGetCurrency (xaccSplitGetParent s)))
-           (acc-comm (xaccAccountGetCommodity (xaccSplitGetAccount s))))
-       (and (not (gnc-commodity-equiv txn-comm acc-comm))
-            (or (not commodity)
-                (gnc-commodity-equiv commodity txn-comm)
-                (gnc-commodity-equiv commodity acc-comm)))))
-   (get-all-splits currency-accounts end-date)))
+  (get-all-commodity-splits currency-accounts end-date commodity #f))
 
 ;; Returns a sorted list of all splits in the 'currency-accounts' up
 ;; to 'end-date' which have the 'commodity' and one other commodity
@@ -96,12 +80,7 @@
 (define (gnc:get-match-commodity-splits-sorted currency-accounts
                                                end-date
                                                commodity)
-  (sort (gnc:get-match-commodity-splits currency-accounts
-                                        end-date commodity)
-        (lambda (a b)
-          (<
-           (xaccTransGetDate (xaccSplitGetParent a))
-           (xaccTransGetDate (xaccSplitGetParent b))))))
+  (get-all-commodity-splits currency-accounts end-date commodity #t))
 
 
 ;; Returns a list of all splits in the currency-accounts up to

commit 68f60fef6803fe1d0153c8af40dd5db835450b84
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Thu Apr 18 00:19:10 2024 +0800

    [engine.i] gnc_get_match_commodity_splits from scheme to c++
    
    The scheme version is very inefficient: (1) it uses QofQuery to
    retrieve all splits, and QofQuery is slow. (2) The whole splitlist
    typically is thousands splits long needs to be converted from C to
    guile via consing and reverse. (3) The scheme list is immediately
    filtered to select "interesting" splits only.
    
    This function performs all of the above using Account's efficient
    methods, selecting only interesting splits into a GList. This list is
    then converted to scheme via cons and reverse.

diff --git a/bindings/engine.i b/bindings/engine.i
index 4ae6c427f3..0546363c68 100644
--- a/bindings/engine.i
+++ b/bindings/engine.i
@@ -41,6 +41,7 @@
 #include "gnc-kvp-guile.h"
 #include "glib-guile.h"
 
+#include "Account.hpp"
 #include "gncAddress.h"
 #include "gncBillTerm.h"
 #include "gncCustomer.h"
@@ -56,6 +57,13 @@
 %}
 #if defined(SWIGGUILE) //Always C++
 %{
+
+using SplitsVec = std::vector<Split*>;
+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);
+
 extern "C"
 {
 SCM scm_init_sw_engine_module (void);
@@ -117,6 +125,28 @@ static const GncGUID * gncPriceGetGUID(GNCPrice *x)
 { return qof_instance_get_guid(QOF_INSTANCE(x)); }
 static const GncGUID * gncBudgetGetGUID(GncBudget *x)
 { return qof_instance_get_guid(QOF_INSTANCE(x)); }
+
+SplitsVec gnc_get_match_commodity_splits (AccountVec accounts, bool use_end_date,
+                                          time64 end_date, gnc_commodity *comm, bool sort)
+{
+    auto match = [use_end_date, end_date, comm](const Split* s) -> bool
+    {
+        if (xaccSplitGetReconcile (s) == VREC) return false;
+        auto trans{xaccSplitGetParent (s)};
+        if (use_end_date && xaccTransGetDate(trans) > end_date) return false;
+        auto txn_comm{xaccTransGetCurrency (trans)};
+        auto acc_comm{xaccAccountGetCommodity (xaccSplitGetAccount (s))};
+        return (txn_comm != acc_comm) && (!comm || comm == txn_comm || comm == acc_comm);
+    };
+    std::vector<Split*> rv;
+    auto maybe_accumulate_split = [&rv, match](auto s){ if (match(s)) rv.push_back (s); };
+    for (const auto acc : accounts)
+        gnc_account_foreach_split (acc, maybe_accumulate_split, true);
+    if (sort)
+        std::sort (rv.begin(), rv.end(), [](auto a, auto b){ return xaccSplitOrder (a, b) < 0; });
+    return rv;
+}
+
 %}
 
 /* NB: The object ownership annotations should already cover all the

commit cb7196a393973b28062600fea70e84996de02edc
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Mon Apr 22 10:13:23 2024 +0800

    [base-typemaps.i] add VECTOR_HELPER_INOUT for Split* and Account*
    
    efficiently convert std::vector<Obj> to/from guile list of objects

diff --git a/bindings/engine.i b/bindings/engine.i
index eb753e8068..4ae6c427f3 100644
--- a/bindings/engine.i
+++ b/bindings/engine.i
@@ -73,6 +73,8 @@ GLIST_HELPER_INOUT(AccountList, SWIGTYPE_p_Account);
 GLIST_HELPER_INOUT(PriceList, SWIGTYPE_p_GNCPrice);
 // TODO: free PriceList?
 GLIST_HELPER_INOUT(CommodityList, SWIGTYPE_p_gnc_commodity);
+VECTOR_HELPER_INOUT(SplitsVec, SWIGTYPE_p_Split, Split);
+VECTOR_HELPER_INOUT(AccountVec, SWIGTYPE_p_Account, Account);
 
 %typemap(newfree) char * "g_free($1);"
 
diff --git a/common/base-typemaps.i b/common/base-typemaps.i
index 5b807f0005..23c2a6cd4b 100644
--- a/common/base-typemaps.i
+++ b/common/base-typemaps.i
@@ -162,6 +162,29 @@ typedef char gchar;
   $result = scm_reverse(list);
 }
 %enddef
+
+
+%define VECTOR_HELPER_INOUT(VectorType, ElemSwigType, ElemType)
+%typemap(in) VectorType {
+  std::vector<ElemType*> accum;
+  for (auto node = $input; !scm_is_null (node); node = scm_cdr (node))
+  {
+      auto p_scm = scm_car (node);
+      auto p = (scm_is_false (p_scm) || scm_is_null (p_scm)) ? static_cast<ElemType*>(nullptr) :
+          static_cast<ElemType*>(SWIG_MustGetPtr(p_scm, ElemSwigType, 1, 0));
+      accum.push_back (p);
+  }
+  accum.swap ($1);
+}
+
+%typemap(out) VectorType {
+  SCM list = SCM_EOL;
+  std::for_each ($1.rbegin(), $1.rend(), [&list](auto n)
+                 { list = scm_cons(SWIG_NewPointerObj(n, ElemSwigType, 0), list); });
+  $result = list;
+}
+%enddef
+
 #elif defined(SWIGPYTHON) /* Typemaps for Python */
 
 %import "glib.h"



Summary of changes:
 bindings/engine.i                                |  32 +++++
 common/base-typemaps.i                           |  23 ++++
 gnucash/report/commodity-utilities.scm           | 152 ++++++++++++-----------
 gnucash/report/reports/standard/balsheet-pnl.scm |  18 +--
 gnucash/report/test/test-commodity-utils.scm     |   8 +-
 5 files changed, 142 insertions(+), 91 deletions(-)



More information about the gnucash-changes mailing list