[engine.i] convert gnc_account_accumulate_at_dates to c++

traversal of account->splits through std::vector instead of scm_list
pull/2078/head
Christopher Lam 1 year ago
parent c01cccbddc
commit ff759c26bc

@ -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)
{

@ -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.

Loading…
Cancel
Save