From b1aa1344ae07cab6814d5f06053b0c7bfdc9861a Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sat, 25 Sep 2004 06:50:18 -0400 Subject: [PATCH] sorting optimization --- ledger.texi | 17 ++++++++++++----- walk.cc | 46 +++++++++++++++++++++++++++++++++++++++++++++- walk.h | 41 +++++++++++++++++++++++++++-------------- 3 files changed, 84 insertions(+), 20 deletions(-) diff --git a/ledger.texi b/ledger.texi index db20cdab..a73aee1d 100644 --- a/ledger.texi +++ b/ledger.texi @@ -1050,14 +1050,14 @@ beginning of the ledger. For food spending just this month (September), use: @example -ledger -d sep balance expenses:food +ledger -p sep balance expenses:food @end example Or maybe I want to see all of my assets, in which case the -s (show sub-accounts) option comes in handy: @example -ledger balance -s +ledger -s balance @end example To exclude a particular account, use a regular expression with a @@ -1068,13 +1068,20 @@ food spending: ledger balance expenses -food @end example -If you want to show all accounts but for one account, remember to use -``--'' to separate the exclusion pattern from the options list: +A query like the following will show the largest expense categories +since a given date: @example -ledger balance -- -equity +ledger -b 2003/10 -s -S -AT -d "T>1000" bal ^expenses -internet @end example +From left to right the options used mean: Show entries since October, +2003; showa all sub-accounts; sort in verse order by the absolute +value of the total; display only accounts with a total value greater +than 1000 units (of whichever commodities the account contains); and +report the balance for all expenses, except for those matching +``internet''. + @node File format, , Typical queries, Running Ledger @section File format diff --git a/walk.cc b/walk.cc index 4469ac67..02f7050d 100644 --- a/walk.cc +++ b/walk.cc @@ -9,6 +9,28 @@ std::list transactions_xdata_ptrs; std::list accounts_xdata; std::list accounts_xdata_ptrs; +template <> +bool compare_items::operator()(const transaction_t * left, + const transaction_t * right) +{ + assert(left); + assert(right); + + transaction_xdata_t& lxdata(transaction_xdata(*left)); + if (! (lxdata.dflags & TRANSACTION_SORT_CALC)) { + sort_order->compute(lxdata.sort_value, details_t(*left)); + lxdata.dflags |= TRANSACTION_SORT_CALC; + } + + transaction_xdata_t& rxdata(transaction_xdata(*right)); + if (! (rxdata.dflags & TRANSACTION_SORT_CALC)) { + sort_order->compute(rxdata.sort_value, details_t(*right)); + rxdata.dflags |= TRANSACTION_SORT_CALC; + } + + return lxdata.sort_value < rxdata.sort_value; +} + void sort_transactions::flush() { std::stable_sort(transactions.begin(), transactions.end(), @@ -123,7 +145,7 @@ static void handle_value(const value_t& value, } } -void determine_amount(value_t& result, balance_pair_t& bal_pair) +static inline void determine_amount(value_t& result, balance_pair_t& bal_pair) { account_xdata_t xdata; xdata.value = bal_pair; @@ -319,6 +341,28 @@ void clear_transactions_xdata() **i = NULL; } +template <> +bool compare_items::operator()(const account_t * left, + const account_t * right) +{ + assert(left); + assert(right); + + account_xdata_t& lxdata(account_xdata(*left)); + if (! (lxdata.dflags & ACCOUNT_SORT_CALC)) { + sort_order->compute(lxdata.sort_value, details_t(*left)); + lxdata.dflags |= ACCOUNT_SORT_CALC; + } + + account_xdata_t& rxdata(account_xdata(*right)); + if (! (rxdata.dflags & ACCOUNT_SORT_CALC)) { + sort_order->compute(rxdata.sort_value, details_t(*right)); + rxdata.dflags |= ACCOUNT_SORT_CALC; + } + + return lxdata.sort_value < rxdata.sort_value; +} + void sum_accounts(account_t& account) { for (accounts_map::iterator i = account.accounts.begin(); diff --git a/walk.h b/walk.h index 42c4ff44..78322ffd 100644 --- a/walk.h +++ b/walk.h @@ -38,28 +38,37 @@ struct item_handler { template class compare_items { - value_t left_result; - value_t right_result; - const value_expr_t * sort_order; - public: compare_items(const value_expr_t * _sort_order) : sort_order(_sort_order) { assert(sort_order); } - - bool operator()(const T * left, const T * right) { - assert(left); - assert(right); - - sort_order->compute(left_result, details_t(*left)); - sort_order->compute(right_result, details_t(*right)); - - return left_result < right_result; - } + bool operator()(const T * left, const T * right); }; +template +bool compare_items::operator()(const T * left, const T * right) +{ + assert(left); + assert(right); + + value_t left_result; + value_t right_result; + sort_order->compute(left_result, details_t(*left)); + sort_order->compute(right_result, details_t(*right)); + + return left_result < right_result; +} + +template <> +bool compare_items::operator()(const transaction_t * left, + const transaction_t * right); + +template <> +bool compare_items::operator()(const account_t * left, + const account_t * right); + ////////////////////////////////////////////////////////////////////// // // Transaction handlers @@ -69,10 +78,12 @@ class compare_items { #define TRANSACTION_TO_DISPLAY 0x0002 #define TRANSACTION_DISPLAYED 0x0004 #define TRANSACTION_NO_TOTAL 0x0008 +#define TRANSACTION_SORT_CALC 0x0010 struct transaction_xdata_t { value_t total; + value_t sort_value; unsigned int index; unsigned short dflags; @@ -400,11 +411,13 @@ class related_transactions : public item_handler #define ACCOUNT_TO_DISPLAY 0x1 #define ACCOUNT_DISPLAYED 0x2 +#define ACCOUNT_SORT_CALC 0x4 struct account_xdata_t { value_t value; value_t total; + value_t sort_value; unsigned int count; // transactions counted toward total unsigned int subcount; unsigned short dflags;