diff options
author | John Wiegley <johnw@newartisans.com> | 2009-11-14 20:43:28 -0500 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2009-11-14 20:43:28 -0500 |
commit | badbeb545b9e700e6656dfbc348bfe1387cb2ffa (patch) | |
tree | 26237a150367e13a24917d994602f5f94f979ec8 /src/xact.cc | |
parent | 73baf9cd727407f6e47b410bbde3b4bcad482ae3 (diff) | |
parent | 8d698e5ccb471d546eee8a5bea6d6c56ec4b08c3 (diff) | |
download | fork-ledger-badbeb545b9e700e6656dfbc348bfe1387cb2ffa.tar.gz fork-ledger-badbeb545b9e700e6656dfbc348bfe1387cb2ffa.tar.bz2 fork-ledger-badbeb545b9e700e6656dfbc348bfe1387cb2ffa.zip |
Merge branch 'next'
Diffstat (limited to 'src/xact.cc')
-rw-r--r-- | src/xact.cc | 84 |
1 files changed, 81 insertions, 3 deletions
diff --git a/src/xact.cc b/src/xact.cc index 1cece187..f2694976 100644 --- a/src/xact.cc +++ b/src/xact.cc @@ -412,7 +412,7 @@ bool xact_base_t::verify() continue; if (post->amount.commodity() == post->cost->commodity()) - throw_(balance_error, + throw_(amount_error, _("A posting's cost must be of a different commodity than its amount")); } @@ -538,6 +538,50 @@ bool xact_t::valid() const return true; } +namespace { + + bool post_pred(expr_t::ptr_op_t op, post_t& post) + { + switch (op->kind) { + case expr_t::op_t::VALUE: + return op->as_value().to_boolean(); + break; + + case expr_t::op_t::O_MATCH: + if (op->left()->kind == expr_t::op_t::IDENT && + op->left()->as_ident() == "account" && + op->right()->kind == expr_t::op_t::VALUE && + op->right()->as_value().is_mask()) + return op->right()->as_value().as_mask() + .match(post.reported_account()->fullname()); + else + break; + + case expr_t::op_t::O_NOT: + return ! post_pred(op->left(), post); + + case expr_t::op_t::O_AND: + return post_pred(op->left(), post) && post_pred(op->right(), post); + + case expr_t::op_t::O_OR: + return post_pred(op->left(), post) || post_pred(op->right(), post); + + case expr_t::op_t::O_QUERY: + if (post_pred(op->left(), post)) + return post_pred(op->right()->left(), post); + else + return post_pred(op->right()->right(), post); + + default: + break; + } + + throw_(calc_error, _("Unhandled operator")); + return false; + } + +} // unnamed namespace + void auto_xact_t::extend_xact(xact_base_t& xact) { posts_list initial_posts(xact.posts.begin(), xact.posts.end()); @@ -547,8 +591,42 @@ void auto_xact_t::extend_xact(xact_base_t& xact) bool needs_further_verification = false; foreach (post_t * initial_post, initial_posts) { - if (! initial_post->has_flags(ITEM_GENERATED) && - predicate(*initial_post)) { + if (initial_post->has_flags(ITEM_GENERATED)) + continue; + + bool matches_predicate = false; + if (try_quick_match) { + try { + bool found_memoized_result = false; + if (! memoized_results.empty()) { + std::map<string, bool>::iterator i = + memoized_results.find(initial_post->account->fullname()); + if (i != memoized_results.end()) { + found_memoized_result = true; + matches_predicate = (*i).second; + } + } + + // Since the majority of people who use automated transactions simply + // match against account names, try using a *much* faster version of + // the predicate evaluator. + if (! found_memoized_result) { + matches_predicate = post_pred(predicate.get_op(), *initial_post); + memoized_results.insert + (std::pair<string, bool>(initial_post->account->fullname(), + matches_predicate)); + } + } + catch (...) { + DEBUG("xact.extend.fail", + "The quick matcher failed, going back to regular eval"); + try_quick_match = false; + matches_predicate = predicate(*initial_post); + } + } else { + matches_predicate = predicate(*initial_post); + } + if (matches_predicate) { foreach (post_t * post, posts) { amount_t post_amount; if (post->amount.is_null()) { |