summaryrefslogtreecommitdiff
path: root/src/xact.cc
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2009-11-14 03:45:18 -0500
committerJohn Wiegley <johnw@newartisans.com>2009-11-14 03:45:18 -0500
commite3064b952029a4fe8f7b65442d23e1112f26bb5f (patch)
treed687508fe98e39a013190e003e6ea33a30f5c36b /src/xact.cc
parentd71f0867f9bdbac8470d8cd0a195cc169d4c248b (diff)
downloadfork-ledger-e3064b952029a4fe8f7b65442d23e1112f26bb5f.tar.gz
fork-ledger-e3064b952029a4fe8f7b65442d23e1112f26bb5f.tar.bz2
fork-ledger-e3064b952029a4fe8f7b65442d23e1112f26bb5f.zip
Spot optimization for simple automated xact exprs
This reduces parsing time in the optimized build by 25%, and was a safe, easy patch. If the "quick predicate evaluator" fails, we disable it from that point on go back to what the standard code does.
Diffstat (limited to 'src/xact.cc')
-rw-r--r--src/xact.cc67
1 files changed, 65 insertions, 2 deletions
diff --git a/src/xact.cc b/src/xact.cc
index 1cece187..330ad38a 100644
--- a/src/xact.cc
+++ b/src/xact.cc
@@ -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,27 @@ 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 {
+ // Since the majority of people who use automated transactions simply
+ // match against account names, try using a *much* faster version of
+ // the predicate evaluator.
+ matches_predicate = post_pred(predicate.get_op(), *initial_post);
+ }
+ 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()) {