[balsheet-pnl] accumulate column data report-dates

Previous would call gnc:account-get-balances-at-dates and
gnc:account-accumulate-at-dates to retrieve balances and
last-split. This commit reduces the O(2*N) operation to O(N) which
becomes significant with accounts with large number of splits.

Maybe we can reduce other account splitlist scans in the future; these
will be easier and would only require augmenting the record.
This commit is contained in:
Christopher Lam 2019-11-24 21:38:42 +08:00
parent a261c8aadb
commit d6a5c8ba54

View File

@ -31,9 +31,18 @@
(use-modules (gnucash gettext)) (use-modules (gnucash gettext))
(use-modules (srfi srfi-1)) (use-modules (srfi srfi-1))
(use-modules (srfi srfi-2)) (use-modules (srfi srfi-2))
(use-modules (srfi srfi-9))
(gnc:module-load "gnucash/report/report-system" 0) (gnc:module-load "gnucash/report/report-system" 0)
;; the column-data record. the gnc:account-accumulate-at-dates will
;; create a record for each report-date with split-data as follows:
(define-record-type :col-datum
(make-datum last-split split-balance)
col-datum?
(last-split col-datum-get-last-split)
(split-balance col-datum-get-split-balance))
(define FOOTER-TEXT (define FOOTER-TEXT
(gnc:make-html-text (gnc:make-html-text
(_ "WARNING: Foreign currency conversions, and unrealized gains (_ "WARNING: Foreign currency conversions, and unrealized gains
@ -770,12 +779,31 @@ also show overall period profit & loss."))
((eq? report-type 'pnl) (list startdate enddate)) ((eq? report-type 'pnl) (list startdate enddate))
(else (list enddate)))) (else (list enddate))))
(accounts-balances (map ;; an alist of (cons account account-cols-data) whereby
(lambda (acc) ;; account-cols-data is a list of col-datum records
(cons acc (accounts-cols-data
(gnc:account-get-balances-at-dates (map
acc report-dates))) (lambda (acc)
accounts)) (let* ((comm (xaccAccountGetCommodity acc))
(amt->monetary (lambda (amt) (gnc:make-gnc-monetary comm amt))))
(cons acc
(gnc:account-accumulate-at-dates
acc report-dates
#:nosplit->elt (make-datum #f (amt->monetary 0))
#:split->elt
(lambda (s)
(make-datum s (amt->monetary (xaccSplitGetBalance s))))))))
accounts))
;; an alist of (cons account account-balances) whereby
;; account-balances is a list of monetary amounts
(accounts-balances
(map
(lambda (acc)
(cons acc (let ((cols-data (assoc-ref accounts-cols-data acc)))
(map col-datum-get-split-balance cols-data))))
accounts))
(exchange-fn (and common-currency (exchange-fn (and common-currency
(gnc:case-exchange-time-fn (gnc:case-exchange-time-fn
price-source common-currency price-source common-currency
@ -906,13 +934,14 @@ also show overall period profit & loss."))
(and account-balance-list (and account-balance-list
(list-ref account-balance-list col-idx))))) (list-ref account-balance-list col-idx)))))
;; an alist of account->last-split at date boundary ;; an alist of (cons account vector-of-splits) where each
;; split is the last one at date boundary
(accounts-splits-dates (accounts-splits-dates
(map (map
(lambda (acc) (lambda (acc)
(cons acc (list->vector (cons acc (let ((cols-data (assoc-ref accounts-cols-data acc)))
(gnc:account-accumulate-at-dates (list->vector
acc report-dates #:split->elt identity)))) (map col-datum-get-last-split cols-data)))))
accounts)) accounts))
(get-cell-anchor-fn (get-cell-anchor-fn