diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | account.cc | 2 | ||||
-rw-r--r-- | amount.cc | 13 | ||||
-rw-r--r-- | autoxact.h | 4 | ||||
-rw-r--r-- | binary.cc | 2 | ||||
-rw-r--r-- | format.cc | 22 | ||||
-rw-r--r-- | format.h | 48 | ||||
-rw-r--r-- | ledger.h | 67 | ||||
-rw-r--r-- | main.cc | 37 | ||||
-rw-r--r-- | valexpr.cc | 63 | ||||
-rw-r--r-- | walk.cc | 163 | ||||
-rw-r--r-- | walk.h | 116 |
12 files changed, 338 insertions, 201 deletions
@@ -24,7 +24,7 @@ CXX = g++ CFLAGS = -Wall -ansi -pedantic #DFLAGS = -O3 -fomit-frame-pointer -DDEBUG_LEVEL=0 -DFLAGS = -g -DDEBUG_LEVEL=4 +DFLAGS = -g -DDEBUG_LEVEL=4 -DDO_CLEANUP #DFLAGS = -g -DDEBUG_LEVEL=2 -pg INCS = -I/sw/include \ @@ -8,6 +8,8 @@ namespace ledger { account_t::~account_t() { DEBUG_PRINT("ledger.memory.ctors", "dtor account_t"); + //assert(! data); + for (accounts_map::iterator i = accounts.begin(); i != accounts.end(); i++) @@ -50,7 +50,7 @@ static struct init_amounts { mpz_init(true_value); mpz_set_ui(true_value, 1); } -#ifndef NO_CLEANUP +#ifdef DO_CLEANUP ~init_amounts() { mpz_clear(true_value); mpz_clear(divisor); @@ -593,8 +593,9 @@ amount_t amount_t::round(unsigned int prec) const } else { amount_t temp = *this; temp._dup(); - mpz_round(MPZ(temp.quantity), MPZ(temp.quantity), quantity->prec, prec); - quantity->prec = prec; + mpz_round(MPZ(temp.quantity), MPZ(temp.quantity), + temp.quantity->prec, prec); + temp.quantity->prec = prec; return temp; } } @@ -929,7 +930,8 @@ commodities_map commodity_t::commodities; commodity_t * commodity_t::null_commodity = commodity_t::find_commodity("", true); -#ifndef NO_CLEANUP +#ifdef DO_CLEANUP + static struct cleanup_commodities { ~cleanup_commodities() { @@ -943,7 +945,8 @@ static struct cleanup_commodities delete (*i).second; } } _cleanup; -#endif + +#endif // DO_CLEANUP commodity_t * commodity_t::find_commodity(const std::string& symbol, bool auto_create) @@ -42,6 +42,10 @@ typedef std::deque<automated_transaction_t *> automated_transactions_deque; class automated_transactions_t { +#ifdef DEBUG_ENABLED + automated_transactions_t(const automated_transactions_t&); +#endif + public: automated_transactions_deque automated_transactions; @@ -9,7 +9,7 @@ namespace ledger { const unsigned long binary_magic_number = 0xFFEED765; -static const unsigned long format_version = 0x00020011; +static const unsigned long format_version = 0x00020012; bool binary_parser_t::test(std::istream& in) const { @@ -21,7 +21,7 @@ std::string partial_account_name(const account_t * account) for (const account_t * acct = account; acct && acct->parent; acct = acct->parent) { - if (acct->dflags & ACCOUNT_DISPLAYED) + if (acct->data && ACCT_DATA(acct)->dflags & ACCOUNT_DISPLAYED) break; if (name.empty()) @@ -35,12 +35,12 @@ std::string partial_account_name(const account_t * account) std::string format_t::date_format = "%Y/%m/%d"; -#ifdef NO_CLEANUP -value_expr_t * format_t::value_expr = NULL; -value_expr_t * format_t::total_expr = NULL; -#else +#ifdef DO_CLEANUP std::auto_ptr<value_expr_t> format_t::value_expr; std::auto_ptr<value_expr_t> format_t::total_expr; +#else +value_expr_t * format_t::value_expr = NULL; +value_expr_t * format_t::total_expr = NULL; #endif element_t * format_t::parse_elements(const std::string& fmt) @@ -186,12 +186,12 @@ void format_t::format_elements(std::ostream& out, case element_t::VALUE_EXPR: { value_expr_t * expr = NULL; switch (elem->type) { -#ifdef NO_CLEANUP - case element_t::VALUE: expr = value_expr; break; - case element_t::TOTAL: expr = total_expr; break; -#else +#ifdef DO_CLEANUP case element_t::VALUE: expr = value_expr.get(); break; case element_t::TOTAL: expr = total_expr.get(); break; +#else + case element_t::VALUE: expr = value_expr; break; + case element_t::TOTAL: expr = total_expr; break; #endif case element_t::VALUE_EXPR: expr = elem->val_expr; break; @@ -336,7 +336,7 @@ void format_t::format_elements(std::ostream& out, for (const account_t * acct = details.account; acct; acct = acct->parent) - if (acct->dflags & ACCOUNT_DISPLAYED) { + if (acct->data && ACCT_DATA(acct)->dflags & ACCOUNT_DISPLAYED) { if (elem->min_width > 0 || elem->max_width > 0) out.width(elem->min_width > elem->max_width ? elem->min_width : elem->max_width); @@ -393,7 +393,7 @@ bool format_account::display_account(const account_t * account, const item_predicate<account_t>& disp_pred) { // Never display an account that has already been displayed. - if (account->dflags & ACCOUNT_DISPLAYED) + if (account->data && ACCT_DATA(account)->dflags & ACCOUNT_DISPLAYED) return false; // At this point, one of two possibilities exists: the account is a @@ -54,12 +54,12 @@ struct format_t static std::string date_format; -#ifdef NO_CLEANUP - static value_expr_t * value_expr; - static value_expr_t * total_expr; -#else +#ifdef DO_CLEANUP static std::auto_ptr<value_expr_t> value_expr; static std::auto_ptr<value_expr_t> total_expr; +#else + static value_expr_t * value_expr; + static value_expr_t * total_expr; #endif format_t(const std::string& _format) : elements(NULL) { @@ -80,19 +80,19 @@ struct format_t void format_elements(std::ostream& out, const details_t& details) const; static void compute_value(value_t& result, const details_t& details) { -#ifdef NO_CLEANUP - if (value_expr) -#else +#ifdef DO_CLEANUP if (value_expr.get()) +#else + if (value_expr) #endif value_expr->compute(result, details); } static void compute_total(value_t& result, const details_t& details) { -#ifdef NO_CLEANUP - if (total_expr) -#else +#ifdef DO_CLEANUP if (total_expr.get()) +#else + if (total_expr) #endif total_expr->compute(result, details); } @@ -118,14 +118,17 @@ class format_transactions : public item_handler<transaction_t> } virtual void operator()(transaction_t * xact) { - if (! (xact->dflags & TRANSACTION_DISPLAYED)) { + if (! xact->data || + ! (XACT_DATA(xact)->dflags & TRANSACTION_DISPLAYED)) { if (last_entry != xact->entry) { first_line_format.format_elements(output_stream, details_t(xact)); last_entry = xact->entry; } else { next_lines_format.format_elements(output_stream, details_t(xact)); } - xact->dflags |= TRANSACTION_DISPLAYED; + if (! xact->data) + xact->data = new transaction_data_t; + XACT_DATA(xact)->dflags |= TRANSACTION_DISPLAYED; } } }; @@ -162,10 +165,14 @@ class format_account : public item_handler<account_t> virtual void operator()(account_t * account) { if (display_account(account, disp_pred)) { if (! account->parent) { - account->dflags |= ACCOUNT_TO_DISPLAY; + if (! account->data) + account->data = new account_data_t; + ACCT_DATA(account)->dflags |= ACCOUNT_TO_DISPLAY; } else { format.format_elements(output_stream, details_t(account)); - account->dflags |= ACCOUNT_DISPLAYED; + if (! account->data) + account->data = new account_data_t; + ACCT_DATA(account)->dflags |= ACCOUNT_DISPLAYED; } } } @@ -198,8 +205,10 @@ class format_equity : public item_handler<account_t> virtual void flush() { account_t summary(NULL, "Equity:Opening Balances"); - summary.value = total; - summary.value.negate(); + std::auto_ptr<account_data_t> acct_data(new account_data_t); + summary.data = acct_data.get(); + ((account_data_t *) summary.data)->value = total; + ((account_data_t *) summary.data)->value.negate(); next_lines_format.format_elements(output_stream, details_t(&summary)); output_stream.flush(); } @@ -207,8 +216,11 @@ class format_equity : public item_handler<account_t> virtual void operator()(account_t * account) { if (format_account::display_account(account, disp_pred)) { next_lines_format.format_elements(output_stream, details_t(account)); - account->dflags |= ACCOUNT_DISPLAYED; - total += account->value; + if (! account->data) + account->data = new account_data_t; + else + total += ACCT_DATA(account)->value; + ACCT_DATA(account)->dflags |= ACCOUNT_DISPLAYED; } } }; @@ -16,16 +16,8 @@ #include <ctime> #include <iostream> -#ifdef DEBUG_LEVEL -#if DEBUG_LEVEL >= 2 #include "debug.h" -#elif DEBUG_LEVEL == 0 -#define NO_CLEANUP 1 -#endif -#endif - #include "amount.h" -#include "value.h" namespace ledger { @@ -35,11 +27,6 @@ namespace ledger { #define TRANSACTION_BALANCE 0x0002 #define TRANSACTION_AUTO 0x0004 -// These flags are only used during formatting, and are not saved -#define TRANSACTION_HANDLED 0x0001 -#define TRANSACTION_DISPLAYED 0x0002 -#define TRANSACTION_NO_TOTAL 0x0004 - class entry_t; class account_t; @@ -52,24 +39,23 @@ class transaction_t amount_t * cost; unsigned short flags; std::string note; - - mutable value_t total; - mutable unsigned int index; - mutable unsigned short dflags; + mutable void * data; transaction_t(account_t * _account) : entry(NULL), account(_account), cost(NULL), - flags(TRANSACTION_NORMAL), index(0), dflags(0) {} + flags(TRANSACTION_NORMAL), data(NULL) { + } transaction_t(account_t * _account, const amount_t& _amount, unsigned int _flags = TRANSACTION_NORMAL, const std::string& _note = "") : entry(NULL), account(_account), amount(_amount), - cost(NULL), flags(_flags), note(_note), index(0), dflags(0) {} + cost(NULL), flags(_flags), note(_note), data(NULL) { + } ~transaction_t() { - DEBUG_PRINT("ledger.memory.dtors", "dtor transaction_t"); + //assert(! data); if (cost) delete cost; } @@ -91,12 +77,8 @@ class entry_t std::string payee; transactions_list transactions; - entry_t() : date(-1), state(UNCLEARED) { - DEBUG_PRINT("ledger.memory.ctors", "ctor entry_t"); - } - + entry_t() : date(-1), state(UNCLEARED) {} ~entry_t() { - DEBUG_PRINT("ledger.memory.dtors", "dtor entry_t"); for (transactions_list::iterator i = transactions.begin(); i != transactions.end(); i++) @@ -114,9 +96,6 @@ class entry_t }; -#define ACCOUNT_DISPLAYED 0x1 -#define ACCOUNT_TO_DISPLAY 0x2 - typedef std::map<const std::string, account_t *> accounts_map; typedef std::pair<const std::string, account_t *> accounts_pair; @@ -125,31 +104,21 @@ class account_t public: typedef unsigned long ident_t; - account_t * parent; - std::string name; - std::string note; - unsigned short depth; - accounts_map accounts; - transactions_list transactions; - - mutable value_t value; - mutable value_t total; - mutable unsigned int count; // transactions counted toward total - mutable unsigned int subcount; - mutable ident_t ident; - mutable unsigned short dflags; - mutable std::string _fullname; - - static ident_t next_ident; + account_t * parent; + std::string name; + std::string note; + unsigned short depth; + accounts_map accounts; + transactions_list transactions; + mutable void * data; + mutable ident_t ident; + mutable std::string _fullname; account_t(account_t * _parent, const std::string& _name = "", const std::string& _note = "") : parent(_parent), name(_name), note(_note), - depth(parent ? parent->depth + 1 : 0), - subcount(0), ident(0), dflags(0) { - DEBUG_PRINT("ledger.memory.ctors", "ctor account_t"); - } + depth(parent ? parent->depth + 1 : 0), data(NULL), ident(0) {} ~account_t(); @@ -198,10 +167,8 @@ class journal_t mutable accounts_map accounts_cache; journal_t() { - DEBUG_PRINT("ledger.memory.ctors", "ctor journal_t"); master = new account_t(NULL, ""); } - ~journal_t(); void add_account(account_t * acct) { @@ -39,7 +39,7 @@ namespace { TIMER_DEF(read_cache, "reading cache file"); } -#ifdef NO_CLEANUP +#ifndef DO_CLEANUP #define auto_ptr bogus_auto_ptr @@ -71,7 +71,7 @@ namespace std { }; } -#endif // NO_CLEANUP +#endif // !DO_CLEANUP static void regexps_to_predicate(std::list<std::string>::const_iterator begin, @@ -369,10 +369,10 @@ int main(int argc, char * argv[], char * envp[]) // Setup the values of %t and %T, used in format strings try { -#ifdef NO_CLEANUP - format_t::value_expr = parse_value_expr(config->value_expr); -#else +#ifdef DO_CLEANUP format_t::value_expr.reset(parse_value_expr(config->value_expr)); +#else + format_t::value_expr = parse_value_expr(config->value_expr); #endif } catch (const value_expr_error& err) { @@ -382,10 +382,10 @@ int main(int argc, char * argv[], char * envp[]) } try { -#ifdef NO_CLEANUP - format_t::total_expr = parse_value_expr(config->total_expr); -#else +#ifdef DO_CLEANUP format_t::total_expr.reset(parse_value_expr(config->total_expr)); +#else + format_t::total_expr = parse_value_expr(config->total_expr); #endif } catch (const value_expr_error& err) { @@ -589,12 +589,14 @@ int main(int argc, char * argv[], char * envp[]) walk_accounts(journal->master, acct_formatter, sort_order.get()); acct_formatter.flush(); - journal->master->value = journal->master->total; + if (journal->master->data) { + ACCT_DATA(journal->master)->value = ACCT_DATA(journal->master)->total; - if (journal->master->dflags & ACCOUNT_TO_DISPLAY) { - std::string end_format = "--------------------\n"; - format.reset(end_format + f); - format.format_elements(OUT(), details_t(journal->master)); + if (ACCT_DATA(journal->master)->dflags & ACCOUNT_TO_DISPLAY) { + std::string end_format = "--------------------\n"; + format.reset(end_format + f); + format.format_elements(OUT(), details_t(journal->master)); + } } } else if (command == "E") { @@ -605,13 +607,14 @@ int main(int argc, char * argv[], char * envp[]) acct_formatter.flush(); } -#ifndef NO_CLEANUP +#ifdef DO_CLEANUP // The transaction display flags (dflags) are not recorded in the // binary cache, and only need to be cleared if the transactions // are to be displayed a second time. - clear_display_flags cleanup; - walk_entries(journal->entries, cleanup); - cleanup.flush(); + clear_transaction_data xact_cleanup; + walk_entries(journal->entries, xact_cleanup); + clear_account_data acct_cleanup; + walk_accounts(journal->master, acct_cleanup); #endif TIMER_STOP(report_gen); @@ -1,4 +1,5 @@ #include "valexpr.h" +#include "walk.h" #include "format.h" #include "error.h" #include "datetime.h" @@ -83,8 +84,8 @@ void value_expr_t::compute(value_t& result, const details_t& details, case AMOUNT: if (details.xact) result = details.xact->amount; - else if (details.account) - result = details.account->value; + else if (details.account && ACCT_DATA(details.account)) + result = ACCT_DATA(details.account)->value; break; case COST: @@ -94,37 +95,37 @@ void value_expr_t::compute(value_t& result, const details_t& details, else result = details.xact->amount; } - else if (details.account) { - result = details.account->value.cost(); + else if (details.account && ACCT_DATA(details.account)) { + result = ACCT_DATA(details.account)->value.cost(); } break; case TOTAL: - if (details.xact) - result = details.xact->total; - else if (details.account) - result = details.account->total; + if (details.xact && XACT_DATA(details.xact)) + result = XACT_DATA(details.xact)->total; + else if (details.account && ACCT_DATA(details.account)) + result = ACCT_DATA(details.account)->total; break; case COST_TOTAL: - if (details.xact) - result = details.xact->total.cost(); - else if (details.account) - result = details.account->total.cost(); + if (details.xact && XACT_DATA(details.xact)) + result = XACT_DATA(details.xact)->total.cost(); + else if (details.account && ACCT_DATA(details.account)) + result = ACCT_DATA(details.account)->total.cost(); break; case VALUE_EXPR: -#ifdef NO_CLEANUP - assert(format_t::value_expr); -#else +#ifdef DO_CLEANUP assert(format_t::value_expr.get()); +#else + assert(format_t::value_expr); #endif format_t::value_expr->compute(result, details); break; case TOTAL_EXPR: -#ifdef NO_CLEANUP - assert(format_t::total_expr); -#else +#ifdef DO_CLEANUP assert(format_t::total_expr.get()); +#else + assert(format_t::total_expr); #endif format_t::total_expr->compute(result, details); break; @@ -173,17 +174,17 @@ void value_expr_t::compute(value_t& result, const details_t& details, break; case INDEX: - if (details.xact) - result = details.xact->index + 1; - else if (details.account) - result = details.account->subcount; + if (details.xact && XACT_DATA(details.xact)) + result = XACT_DATA(details.xact)->index + 1; + else if (details.account && ACCT_DATA(details.account)) + result = ACCT_DATA(details.account)->subcount; break; case COUNT: - if (details.xact) - result = details.xact->index + 1; - else if (details.account) - result = details.account->count; + if (details.xact && XACT_DATA(details.xact)) + result = XACT_DATA(details.xact)->index + 1; + else if (details.account && ACCT_DATA(details.account)) + result = ACCT_DATA(details.account)->count; break; case DEPTH: @@ -194,15 +195,17 @@ void value_expr_t::compute(value_t& result, const details_t& details, break; case F_ARITH_MEAN: - if (details.xact) { + if (details.xact && XACT_DATA(details.xact)) { assert(left); left->compute(result, details); - result /= amount_t(details.xact->index + 1); + result /= amount_t(XACT_DATA(details.xact)->index + 1); } - else if (details.account && details.account->count) { + else if (details.account && + ACCT_DATA(details.account) && + ACCT_DATA(details.account)->count) { assert(left); left->compute(result, details); - result /= amount_t(details.account->count); + result /= amount_t(ACCT_DATA(details.account)->count); } break; @@ -20,11 +20,14 @@ void sort_transactions::flush() void calc_transactions::operator()(transaction_t * xact) { - if (last_xact) { - xact->total += last_xact->total; - xact->index = last_xact->index + 1; + if (! xact->data) + xact->data = new transaction_data_t; + + if (last_xact && last_xact->data) { + XACT_DATA(xact)->total += XACT_DATA(last_xact)->total; + XACT_DATA(xact)->index = XACT_DATA(last_xact)->index + 1; } else { - xact->index = 0; + XACT_DATA(xact)->index = 0; } if (inverted) { @@ -33,8 +36,8 @@ void calc_transactions::operator()(transaction_t * xact) xact->cost->negate(); } - if (! (xact->dflags & TRANSACTION_NO_TOTAL)) - xact->total += *xact; + if (! (XACT_DATA(xact)->dflags & TRANSACTION_NO_TOTAL)) + XACT_DATA(xact)->total += *xact; (*handler)(xact); @@ -47,6 +50,80 @@ void calc_transactions::operator()(transaction_t * xact) last_xact = xact; } + +static void handle_value(const value_t& value, account_t * account, + entry_t * entry, unsigned int flags, + transactions_deque& temps, + item_handler<transaction_t> * handler) +{ + balance_t * bal = NULL; + + switch (value.type) { + case value_t::BOOLEAN: + case value_t::INTEGER: + case value_t::AMOUNT: { + transaction_t * xact = new transaction_t(account); + temps.push_back(xact); + + xact->entry = entry; + switch (value.type) { + case value_t::BOOLEAN: + xact->amount = *((bool *) value.data); + break; + case value_t::INTEGER: + xact->amount = *((unsigned int *) value.data); + break; + case value_t::AMOUNT: + xact->amount = *((amount_t *) value.data); + break; + default: + assert(0); + break; + } + + if (flags) { + if (! xact->data) + xact->data = new transaction_data_t; + XACT_DATA(xact)->dflags |= flags; + } + + (*handler)(xact); + break; + } + + case value_t::BALANCE_PAIR: + bal = &((balance_pair_t *) value.data)->quantity; + // fall through... + + case value_t::BALANCE: + if (! bal) + bal = (balance_t *) value.data; + + for (amounts_map::const_iterator i = bal->amounts.begin(); + i != bal->amounts.end(); + i++) { + transaction_t * xact = new transaction_t(account); + temps.push_back(xact); + + xact->entry = entry; + xact->amount = (*i).second; + + if (flags) { + if (! xact->data) + xact->data = new transaction_data_t; + XACT_DATA(xact)->dflags |= flags; + } + + (*handler)(xact); + } + break; + + default: + assert(0); + break; + } +} + void collapse_transactions::report_cumulative_subtotal() { if (count == 1) { @@ -54,23 +131,12 @@ void collapse_transactions::report_cumulative_subtotal() } else { assert(count > 1); - totals_account->total = subtotal; + if (! totals_account->data) + totals_account->data = new account_data_t; + ACCT_DATA(totals_account)->total = subtotal; value_t result; format_t::compute_total(result, details_t(totals_account)); - -#if 0 - for (amounts_map::const_iterator i = result.amounts.begin(); - i != result.amounts.end(); - i++) { - transaction_t * total_xact = new transaction_t(totals_account); - xact_temps.push_back(total_xact); - - total_xact->entry = last_entry; - total_xact->amount = (*i).second; - - (*handler)(total_xact); - } -#endif + handle_value(result, totals_account, last_entry, 0, xact_temps, handler); } subtotal = 0; @@ -99,26 +165,17 @@ void changed_value_transactions::operator()(transaction_t * xact) entry->payee = "Commodities revalued"; entry->date = current; -#if 0 - for (amounts_map::const_iterator i = diff.amounts.begin(); - i != diff.amounts.end(); - i++) { - transaction_t * temp_xact = new transaction_t(NULL); - xact_temps.push_back(temp_xact); - - temp_xact->entry = entry; - temp_xact->amount = (*i).second; - temp_xact->dflags |= TRANSACTION_NO_TOTAL; - - (*handler)(temp_xact); - } -#endif + handle_value(cur_bal, NULL, entry, TRANSACTION_NO_TOTAL, xact_temps, + handler); } } if (xact) { - if (changed_values_only) - xact->dflags |= TRANSACTION_DISPLAYED; + if (changed_values_only) { + if (! xact->data) + xact->data = new transaction_data_t; + XACT_DATA(xact)->dflags |= TRANSACTION_DISPLAYED; + } (*handler)(xact); } @@ -151,27 +208,23 @@ void subtotal_transactions::flush(const char * spec_fmt) for (balances_map::iterator i = balances.begin(); i != balances.end(); i++) { - entry->date = finish; - transaction_t temp((*i).first); - temp.entry = entry; - temp.total = (*i).second; value_t result; - format_t::compute_total(result, details_t(&temp)); - entry->date = start; - -#if 0 - for (amounts_map::const_iterator j = result.amounts.begin(); - j != result.amounts.end(); - j++) { - transaction_t * xact = new transaction_t((*i).first); - xact_temps.push_back(xact); - - xact->entry = entry; - xact->amount = (*j).second; - (*handler)(xact); + entry->date = finish; + { + transaction_t temp((*i).first); + temp.entry = entry; + { + std::auto_ptr<transaction_data_t> xact_data(new transaction_data_t); + temp.data = xact_data.get(); + ((transaction_data_t *) temp.data)->total = (*i).second; + format_t::compute_total(result, details_t(&temp)); + } + temp.data = NULL; } -#endif + entry->date = start; + + handle_value(result, (*i).first, entry, 0, xact_temps, handler); } balances.clear(); @@ -104,17 +104,67 @@ inline void walk_entries(entries_list& list, ////////////////////////////////////////////////////////////////////// +#define TRANSACTION_HANDLED 0x0001 +#define TRANSACTION_DISPLAYED 0x0002 +#define TRANSACTION_NO_TOTAL 0x0004 + +struct transaction_data_t +{ + value_t total; + unsigned int index; + unsigned short dflags; + + transaction_data_t() : index(0), dflags(0) { + DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_data_t"); + } +#ifdef DEBUG_ENABLED + ~transaction_data_t() { + DEBUG_PRINT("ledger.memory.dtors", "dtor transaction_data_t"); + } +#endif +}; + +#define XACT_DATA(xact) ((transaction_data_t *) ((xact)->data)) + +#define ACCOUNT_DISPLAYED 0x1 +#define ACCOUNT_TO_DISPLAY 0x2 + +struct account_data_t +{ + value_t value; + value_t total; + unsigned int count; // transactions counted toward total + unsigned int subcount; + unsigned short dflags; + + account_data_t() : count(0), subcount(0), dflags(0) { + DEBUG_PRINT("ledger.memory.ctors", "ctor account_data_t"); + } +#ifdef DEBUG_ENABLED + ~account_data_t() { + DEBUG_PRINT("ledger.memory.dtors", "dtor account_data_t"); + } +#endif +}; + +#define ACCT_DATA(acct) ((account_data_t *) ((acct)->data)) + +////////////////////////////////////////////////////////////////////// + class ignore_transactions : public item_handler<transaction_t> { public: virtual void operator()(transaction_t * xact) {} }; -class clear_display_flags : public item_handler<transaction_t> +class clear_transaction_data : public item_handler<transaction_t> { public: virtual void operator()(transaction_t * xact) { - xact->dflags = 0; + if (xact->data) { + delete (transaction_data_t *) xact->data; + xact->data = NULL; + } } }; @@ -125,8 +175,11 @@ class set_account_value : public item_handler<transaction_t> : item_handler<transaction_t>(handler) {} virtual void operator()(transaction_t * xact) { - xact->account->value += *xact; - xact->account->subcount++; + if (! ACCT_DATA(xact->account)) + xact->account->data = new account_data_t; + + ACCT_DATA(xact->account)->value += *xact; + ACCT_DATA(xact->account)->subcount++; if (handler) (*handler)(xact); @@ -196,11 +249,20 @@ class collapse_transactions : public item_handler<transaction_t> } virtual ~collapse_transactions() { + if (totals_account->data) { + delete (account_data_t *) totals_account->data; + totals_account->data = NULL; + } delete totals_account; for (transactions_deque::iterator i = xact_temps.begin(); i != xact_temps.end(); - i++) + i++) { + if ((*i)->data) { + delete (transaction_data_t *) (*i)->data; + (*i)->data = NULL; + } delete *i; + } } virtual void flush() { @@ -250,8 +312,13 @@ class changed_value_transactions : public item_handler<transaction_t> for (transactions_deque::iterator i = xact_temps.begin(); i != xact_temps.end(); - i++) + i++) { + if ((*i)->data) { + delete (transaction_data_t *) (*i)->data; + (*i)->data = NULL; + } delete *i; + } } virtual void flush() { @@ -286,8 +353,13 @@ class subtotal_transactions : public item_handler<transaction_t> for (transactions_deque::iterator i = xact_temps.begin(); i != xact_temps.end(); - i++) + i++) { + if ((*i)->data) { + delete (transaction_data_t *) (*i)->data; + (*i)->data = NULL; + } delete *i; + } } void flush(const char * spec_fmt); @@ -348,10 +420,13 @@ class related_transactions : public item_handler<transaction_t> for (transactions_list::iterator i = xact->entry->transactions.begin(); i != xact->entry->transactions.end(); i++) - if (! ((*i)->dflags & TRANSACTION_HANDLED) && + if ((! (*i)->data || + ! (XACT_DATA(*i)->dflags & TRANSACTION_HANDLED)) && (*i == xact ? also_matching : ! ((*i)->flags & TRANSACTION_AUTO))) { - (*i)->dflags |= TRANSACTION_HANDLED; + if (! (*i)->data) + (*i)->data = new transaction_data_t; + XACT_DATA(*i)->dflags |= TRANSACTION_HANDLED; (*handler)(*i); } } @@ -363,16 +438,31 @@ class related_transactions : public item_handler<transaction_t> // Account walking functions // +class clear_account_data : public item_handler<account_t> +{ + public: + virtual void operator()(account_t * account) { + if (account->data) { + delete (account_data_t *) account->data; + account->data = NULL; + } + } +}; + inline void sum_accounts(account_t * account) { + if (! account->data) + account->data = new account_data_t; + for (accounts_map::iterator i = account->accounts.begin(); i != account->accounts.end(); i++) { sum_accounts((*i).second); - account->total += (*i).second->total; - account->count += (*i).second->count + (*i).second->subcount; + ACCT_DATA(account)->total += ACCT_DATA((*i).second)->total; + ACCT_DATA(account)->count += (ACCT_DATA((*i).second)->count + + ACCT_DATA((*i).second)->subcount); } - account->total += account->value; - account->count += account->subcount; + ACCT_DATA(account)->total += ACCT_DATA(account)->value; + ACCT_DATA(account)->count += ACCT_DATA(account)->subcount; } typedef std::deque<account_t *> accounts_deque; |