Skip to content

Commit 5c1ddbe

Browse files
[engine.i] convert gnc_account_accumulate_at_dates to c++
traversal of account->splits through std::vector instead of scm_list
1 parent cc45a8a commit 5c1ddbe

File tree

2 files changed

+64
-35
lines changed

2 files changed

+64
-35
lines changed

bindings/engine.i

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,22 @@ using AccountVec = std::vector<Account*>;
6666
SplitsVec gnc_get_match_commodity_splits (AccountVec accounts, bool use_end_date,
6767
time64 end_date, gnc_commodity *comm, bool sort);
6868

69+
/* scans account splits, in posted date order, calling split_fn(split)
70+
at each split and accumulate the result at each date in the SCM
71+
list dates into a new SCM list. Parameters are:
72+
73+
acc the account
74+
dates the SCM list of posted dates, assumed to be in chronological order
75+
init the result to be pushed into the result for dates prior to first split date
76+
split_fn the split->elt procedure whose result of (split_fn split) will be pushed
77+
into the returned SCM list */
78+
SCM gnc_account_accumulate_to_dates (const Account *acc, SCM dates,
79+
SCM split_fn, SCM init);
80+
81+
/* as above, but the split_to_date function to use a different date order. */
82+
SCM gnc_account_accumulate_to_dates (const Account *acc, SCM dates,
83+
SCM split_fn, SCM init, SCM split_to_date);
84+
6985
AccountVec gnc_accounts_and_all_descendants (AccountVec accounts);
7086

7187
extern "C"
@@ -160,6 +176,51 @@ SplitsVec gnc_get_match_commodity_splits (AccountVec accounts, bool use_end_date
160176
return rv;
161177
}
162178

179+
static SCM
180+
accumulate_splits_by_dates (const SplitsVec& splits, SCM dates, SCM result,
181+
std::function<bool(Split*,SCM)> no_later_than_date,
182+
std::function<SCM(Split*)> get_result)
183+
{
184+
SCM rv = SCM_EOL;
185+
auto splits_it = splits.begin();
186+
for (; !scm_is_null(dates); dates = scm_cdr (dates))
187+
{
188+
while (splits_it != splits.end() && no_later_than_date (*splits_it, scm_car (dates)))
189+
result = get_result (*splits_it++);
190+
191+
rv = scm_cons (result, rv);
192+
}
193+
return scm_reverse_x (rv, SCM_EOL);
194+
}
195+
196+
SCM
197+
gnc_account_accumulate_to_dates (const Account *acc, SCM dates,
198+
SCM split_fn, SCM init)
199+
{
200+
const auto& splits = xaccAccountGetSplits(acc);
201+
auto get_result = [&](Split* s) -> SCM { return scm_call_1(split_fn, gnc_split_to_scm(s)); };
202+
auto no_later_than_date = [&](Split* s, SCM date) -> bool
203+
{ return xaccTransGetDate (xaccSplitGetParent (s)) <= scm_to_int64 (date); };
204+
205+
return accumulate_splits_by_dates (splits, dates, init, no_later_than_date, get_result);
206+
}
207+
208+
SCM
209+
gnc_account_accumulate_to_dates (const Account *acc, SCM dates,
210+
SCM split_fn, SCM init, SCM split_to_date)
211+
{
212+
auto splits = xaccAccountGetSplits(acc);
213+
auto less_scm = [](SCM a, SCM b) -> bool { return scm_is_true(scm_less_p(a, b)); };
214+
auto get_date = [&](Split* s) -> SCM { return scm_call_1(split_to_date, gnc_split_to_scm(s)); };
215+
auto get_result = [&](Split* s) -> SCM { return scm_call_1(split_fn, gnc_split_to_scm(s)); };
216+
auto no_later_than_date = [&](auto s, SCM date) -> bool { return !less_scm(date, get_date(s)); };
217+
std::sort(splits.begin(), splits.end(), [&](auto a, auto b) -> bool
218+
{ return less_scm(get_date(a), get_date(b)); });
219+
220+
return accumulate_splits_by_dates (splits, dates, init, no_later_than_date, get_result);
221+
}
222+
223+
163224
using AccountSet = std::unordered_set<Account*>;
164225
static void maybe_add_descendants (Account* acc, AccountSet* accset)
165226
{

gnucash/report/report-utilities.scm

Lines changed: 3 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -476,41 +476,9 @@
476476
(nosplit->elt #f)
477477
(split->date #f)
478478
(split->elt xaccSplitGetBalance))
479-
(define to-date (or split->date (compose xaccTransGetDate xaccSplitGetParent)))
480-
(define (less? a b) (< (to-date a) (to-date b)))
481-
482-
(let lp ((splits (if split->date
483-
(sort (xaccAccountGetSplits acc) less?)
484-
(xaccAccountGetSplits acc)))
485-
(dates (sort dates <))
486-
(result '())
487-
(last-result nosplit->elt))
488-
(match dates
489-
490-
;; end of dates. job done!
491-
(() (reverse result))
492-
493-
((date . rest)
494-
(define (before-date? s) (<= (to-date s) date))
495-
(define (after-date? s) (< date (to-date s)))
496-
(cond
497-
498-
;; end of splits, but still has dates. pad with last-result
499-
;; until end of dates.
500-
((null? splits) (lp '() rest (cons last-result result) last-result))
501-
502-
;; the next split is still before date.
503-
((and (pair? (cdr splits)) (before-date? (cadr splits)))
504-
(lp (cdr splits) dates result (split->elt (car splits))))
505-
506-
;; head split after date, accumulate previous result
507-
((after-date? (car splits))
508-
(lp splits rest (cons last-result result) last-result))
509-
510-
;; head split before date, next split after date, or end.
511-
(else
512-
(let ((head-result (split->elt (car splits))))
513-
(lp (cdr splits) rest (cons head-result result) head-result))))))))
479+
(if split->date
480+
(gnc-account-accumulate-to-dates acc dates split->elt nosplit->elt split->date)
481+
(gnc-account-accumulate-to-dates acc dates split->elt nosplit->elt)))
514482

515483
;; This works similar as above but returns a commodity-collector,
516484
;; thus takes care of children accounts with different currencies.

0 commit comments

Comments
 (0)