a little more reorganizing, but only fractionally faster. diminishing returns!

This commit is contained in:
John Wiegley 2004-08-22 02:13:41 -04:00
parent 6d5333b896
commit 5619a1d5be
12 changed files with 338 additions and 201 deletions

View file

@ -24,7 +24,7 @@ CXX = g++
CFLAGS = -Wall -ansi -pedantic CFLAGS = -Wall -ansi -pedantic
#DFLAGS = -O3 -fomit-frame-pointer -DDEBUG_LEVEL=0 #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 #DFLAGS = -g -DDEBUG_LEVEL=2 -pg
INCS = -I/sw/include \ INCS = -I/sw/include \

View file

@ -8,6 +8,8 @@ namespace ledger {
account_t::~account_t() account_t::~account_t()
{ {
DEBUG_PRINT("ledger.memory.ctors", "dtor account_t"); DEBUG_PRINT("ledger.memory.ctors", "dtor account_t");
//assert(! data);
for (accounts_map::iterator i = accounts.begin(); for (accounts_map::iterator i = accounts.begin();
i != accounts.end(); i != accounts.end();
i++) i++)

View file

@ -50,7 +50,7 @@ static struct init_amounts {
mpz_init(true_value); mpz_init(true_value);
mpz_set_ui(true_value, 1); mpz_set_ui(true_value, 1);
} }
#ifndef NO_CLEANUP #ifdef DO_CLEANUP
~init_amounts() { ~init_amounts() {
mpz_clear(true_value); mpz_clear(true_value);
mpz_clear(divisor); mpz_clear(divisor);
@ -593,8 +593,9 @@ amount_t amount_t::round(unsigned int prec) const
} else { } else {
amount_t temp = *this; amount_t temp = *this;
temp._dup(); temp._dup();
mpz_round(MPZ(temp.quantity), MPZ(temp.quantity), quantity->prec, prec); mpz_round(MPZ(temp.quantity), MPZ(temp.quantity),
quantity->prec = prec; temp.quantity->prec, prec);
temp.quantity->prec = prec;
return temp; return temp;
} }
} }
@ -929,7 +930,8 @@ commodities_map commodity_t::commodities;
commodity_t * commodity_t::null_commodity = commodity_t * commodity_t::null_commodity =
commodity_t::find_commodity("", true); commodity_t::find_commodity("", true);
#ifndef NO_CLEANUP #ifdef DO_CLEANUP
static struct cleanup_commodities static struct cleanup_commodities
{ {
~cleanup_commodities() { ~cleanup_commodities() {
@ -943,7 +945,8 @@ static struct cleanup_commodities
delete (*i).second; delete (*i).second;
} }
} _cleanup; } _cleanup;
#endif
#endif // DO_CLEANUP
commodity_t * commodity_t::find_commodity(const std::string& symbol, commodity_t * commodity_t::find_commodity(const std::string& symbol,
bool auto_create) bool auto_create)

View file

@ -42,6 +42,10 @@ typedef std::deque<automated_transaction_t *> automated_transactions_deque;
class automated_transactions_t class automated_transactions_t
{ {
#ifdef DEBUG_ENABLED
automated_transactions_t(const automated_transactions_t&);
#endif
public: public:
automated_transactions_deque automated_transactions; automated_transactions_deque automated_transactions;

View file

@ -9,7 +9,7 @@
namespace ledger { namespace ledger {
const unsigned long binary_magic_number = 0xFFEED765; 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 bool binary_parser_t::test(std::istream& in) const
{ {

View file

@ -21,7 +21,7 @@ std::string partial_account_name(const account_t * account)
for (const account_t * acct = account; for (const account_t * acct = account;
acct && acct->parent; acct && acct->parent;
acct = acct->parent) { acct = acct->parent) {
if (acct->dflags & ACCOUNT_DISPLAYED) if (acct->data && ACCT_DATA(acct)->dflags & ACCOUNT_DISPLAYED)
break; break;
if (name.empty()) 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"; std::string format_t::date_format = "%Y/%m/%d";
#ifdef NO_CLEANUP #ifdef DO_CLEANUP
value_expr_t * format_t::value_expr = NULL;
value_expr_t * format_t::total_expr = NULL;
#else
std::auto_ptr<value_expr_t> format_t::value_expr; std::auto_ptr<value_expr_t> format_t::value_expr;
std::auto_ptr<value_expr_t> format_t::total_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 #endif
element_t * format_t::parse_elements(const std::string& fmt) 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: { case element_t::VALUE_EXPR: {
value_expr_t * expr = NULL; value_expr_t * expr = NULL;
switch (elem->type) { switch (elem->type) {
#ifdef NO_CLEANUP #ifdef DO_CLEANUP
case element_t::VALUE: expr = value_expr; break;
case element_t::TOTAL: expr = total_expr; break;
#else
case element_t::VALUE: expr = value_expr.get(); break; case element_t::VALUE: expr = value_expr.get(); break;
case element_t::TOTAL: expr = total_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 #endif
case element_t::VALUE_EXPR: expr = elem->val_expr; break; 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; for (const account_t * acct = details.account;
acct; acct;
acct = acct->parent) 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) if (elem->min_width > 0 || elem->max_width > 0)
out.width(elem->min_width > elem->max_width ? out.width(elem->min_width > elem->max_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) const item_predicate<account_t>& disp_pred)
{ {
// Never display an account that has already been displayed. // 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; return false;
// At this point, one of two possibilities exists: the account is a // At this point, one of two possibilities exists: the account is a

View file

@ -54,12 +54,12 @@ struct format_t
static std::string date_format; static std::string date_format;
#ifdef NO_CLEANUP #ifdef DO_CLEANUP
static value_expr_t * value_expr;
static value_expr_t * total_expr;
#else
static std::auto_ptr<value_expr_t> value_expr; static std::auto_ptr<value_expr_t> value_expr;
static std::auto_ptr<value_expr_t> total_expr; static std::auto_ptr<value_expr_t> total_expr;
#else
static value_expr_t * value_expr;
static value_expr_t * total_expr;
#endif #endif
format_t(const std::string& _format) : elements(NULL) { 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; void format_elements(std::ostream& out, const details_t& details) const;
static void compute_value(value_t& result, const details_t& details) { static void compute_value(value_t& result, const details_t& details) {
#ifdef NO_CLEANUP #ifdef DO_CLEANUP
if (value_expr)
#else
if (value_expr.get()) if (value_expr.get())
#else
if (value_expr)
#endif #endif
value_expr->compute(result, details); value_expr->compute(result, details);
} }
static void compute_total(value_t& result, const details_t& details) { static void compute_total(value_t& result, const details_t& details) {
#ifdef NO_CLEANUP #ifdef DO_CLEANUP
if (total_expr)
#else
if (total_expr.get()) if (total_expr.get())
#else
if (total_expr)
#endif #endif
total_expr->compute(result, details); total_expr->compute(result, details);
} }
@ -118,14 +118,17 @@ class format_transactions : public item_handler<transaction_t>
} }
virtual void operator()(transaction_t * xact) { 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) { if (last_entry != xact->entry) {
first_line_format.format_elements(output_stream, details_t(xact)); first_line_format.format_elements(output_stream, details_t(xact));
last_entry = xact->entry; last_entry = xact->entry;
} else { } else {
next_lines_format.format_elements(output_stream, details_t(xact)); 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) { virtual void operator()(account_t * account) {
if (display_account(account, disp_pred)) { if (display_account(account, disp_pred)) {
if (! account->parent) { 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 { } else {
format.format_elements(output_stream, details_t(account)); 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() { virtual void flush() {
account_t summary(NULL, "Equity:Opening Balances"); account_t summary(NULL, "Equity:Opening Balances");
summary.value = total; std::auto_ptr<account_data_t> acct_data(new account_data_t);
summary.value.negate(); 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)); next_lines_format.format_elements(output_stream, details_t(&summary));
output_stream.flush(); output_stream.flush();
} }
@ -207,8 +216,11 @@ class format_equity : public item_handler<account_t>
virtual void operator()(account_t * account) { virtual void operator()(account_t * account) {
if (format_account::display_account(account, disp_pred)) { if (format_account::display_account(account, disp_pred)) {
next_lines_format.format_elements(output_stream, details_t(account)); next_lines_format.format_elements(output_stream, details_t(account));
account->dflags |= ACCOUNT_DISPLAYED; if (! account->data)
total += account->value; account->data = new account_data_t;
else
total += ACCT_DATA(account)->value;
ACCT_DATA(account)->dflags |= ACCOUNT_DISPLAYED;
} }
} }
}; };

View file

@ -16,16 +16,8 @@
#include <ctime> #include <ctime>
#include <iostream> #include <iostream>
#ifdef DEBUG_LEVEL
#if DEBUG_LEVEL >= 2
#include "debug.h" #include "debug.h"
#elif DEBUG_LEVEL == 0
#define NO_CLEANUP 1
#endif
#endif
#include "amount.h" #include "amount.h"
#include "value.h"
namespace ledger { namespace ledger {
@ -35,11 +27,6 @@ namespace ledger {
#define TRANSACTION_BALANCE 0x0002 #define TRANSACTION_BALANCE 0x0002
#define TRANSACTION_AUTO 0x0004 #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 entry_t;
class account_t; class account_t;
@ -52,24 +39,23 @@ class transaction_t
amount_t * cost; amount_t * cost;
unsigned short flags; unsigned short flags;
std::string note; std::string note;
mutable void * data;
mutable value_t total;
mutable unsigned int index;
mutable unsigned short dflags;
transaction_t(account_t * _account) transaction_t(account_t * _account)
: entry(NULL), account(_account), cost(NULL), : entry(NULL), account(_account), cost(NULL),
flags(TRANSACTION_NORMAL), index(0), dflags(0) {} flags(TRANSACTION_NORMAL), data(NULL) {
}
transaction_t(account_t * _account, transaction_t(account_t * _account,
const amount_t& _amount, const amount_t& _amount,
unsigned int _flags = TRANSACTION_NORMAL, unsigned int _flags = TRANSACTION_NORMAL,
const std::string& _note = "") const std::string& _note = "")
: entry(NULL), account(_account), amount(_amount), : 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() { ~transaction_t() {
DEBUG_PRINT("ledger.memory.dtors", "dtor transaction_t"); //assert(! data);
if (cost) if (cost)
delete cost; delete cost;
} }
@ -91,12 +77,8 @@ class entry_t
std::string payee; std::string payee;
transactions_list transactions; transactions_list transactions;
entry_t() : date(-1), state(UNCLEARED) { entry_t() : date(-1), state(UNCLEARED) {}
DEBUG_PRINT("ledger.memory.ctors", "ctor entry_t");
}
~entry_t() { ~entry_t() {
DEBUG_PRINT("ledger.memory.dtors", "dtor entry_t");
for (transactions_list::iterator i = transactions.begin(); for (transactions_list::iterator i = transactions.begin();
i != transactions.end(); i != transactions.end();
i++) 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::map<const std::string, account_t *> accounts_map;
typedef std::pair<const std::string, account_t *> accounts_pair; typedef std::pair<const std::string, account_t *> accounts_pair;
@ -131,25 +110,15 @@ class account_t
unsigned short depth; unsigned short depth;
accounts_map accounts; accounts_map accounts;
transactions_list transactions; transactions_list transactions;
mutable void * data;
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 ident_t ident;
mutable unsigned short dflags;
mutable std::string _fullname; mutable std::string _fullname;
static ident_t next_ident;
account_t(account_t * _parent, account_t(account_t * _parent,
const std::string& _name = "", const std::string& _name = "",
const std::string& _note = "") const std::string& _note = "")
: parent(_parent), name(_name), note(_note), : parent(_parent), name(_name), note(_note),
depth(parent ? parent->depth + 1 : 0), depth(parent ? parent->depth + 1 : 0), data(NULL), ident(0) {}
subcount(0), ident(0), dflags(0) {
DEBUG_PRINT("ledger.memory.ctors", "ctor account_t");
}
~account_t(); ~account_t();
@ -198,10 +167,8 @@ class journal_t
mutable accounts_map accounts_cache; mutable accounts_map accounts_cache;
journal_t() { journal_t() {
DEBUG_PRINT("ledger.memory.ctors", "ctor journal_t");
master = new account_t(NULL, ""); master = new account_t(NULL, "");
} }
~journal_t(); ~journal_t();
void add_account(account_t * acct) { void add_account(account_t * acct) {

31
main.cc
View file

@ -39,7 +39,7 @@ namespace {
TIMER_DEF(read_cache, "reading cache file"); TIMER_DEF(read_cache, "reading cache file");
} }
#ifdef NO_CLEANUP #ifndef DO_CLEANUP
#define auto_ptr bogus_auto_ptr #define auto_ptr bogus_auto_ptr
@ -71,7 +71,7 @@ namespace std {
}; };
} }
#endif // NO_CLEANUP #endif // !DO_CLEANUP
static void static void
regexps_to_predicate(std::list<std::string>::const_iterator begin, 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 // Setup the values of %t and %T, used in format strings
try { try {
#ifdef NO_CLEANUP #ifdef DO_CLEANUP
format_t::value_expr = parse_value_expr(config->value_expr);
#else
format_t::value_expr.reset(parse_value_expr(config->value_expr)); format_t::value_expr.reset(parse_value_expr(config->value_expr));
#else
format_t::value_expr = parse_value_expr(config->value_expr);
#endif #endif
} }
catch (const value_expr_error& err) { catch (const value_expr_error& err) {
@ -382,10 +382,10 @@ int main(int argc, char * argv[], char * envp[])
} }
try { try {
#ifdef NO_CLEANUP #ifdef DO_CLEANUP
format_t::total_expr = parse_value_expr(config->total_expr);
#else
format_t::total_expr.reset(parse_value_expr(config->total_expr)); format_t::total_expr.reset(parse_value_expr(config->total_expr));
#else
format_t::total_expr = parse_value_expr(config->total_expr);
#endif #endif
} }
catch (const value_expr_error& err) { catch (const value_expr_error& err) {
@ -589,14 +589,16 @@ int main(int argc, char * argv[], char * envp[])
walk_accounts(journal->master, acct_formatter, sort_order.get()); walk_accounts(journal->master, acct_formatter, sort_order.get());
acct_formatter.flush(); 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) { if (ACCT_DATA(journal->master)->dflags & ACCOUNT_TO_DISPLAY) {
std::string end_format = "--------------------\n"; std::string end_format = "--------------------\n";
format.reset(end_format + f); format.reset(end_format + f);
format.format_elements(OUT(), details_t(journal->master)); format.format_elements(OUT(), details_t(journal->master));
} }
} }
}
else if (command == "E") { else if (command == "E") {
format_equity acct_formatter(OUT(), format, nformat, format_equity acct_formatter(OUT(), format, nformat,
config->display_predicate); config->display_predicate);
@ -605,13 +607,14 @@ int main(int argc, char * argv[], char * envp[])
acct_formatter.flush(); acct_formatter.flush();
} }
#ifndef NO_CLEANUP #ifdef DO_CLEANUP
// The transaction display flags (dflags) are not recorded in the // The transaction display flags (dflags) are not recorded in the
// binary cache, and only need to be cleared if the transactions // binary cache, and only need to be cleared if the transactions
// are to be displayed a second time. // are to be displayed a second time.
clear_display_flags cleanup; clear_transaction_data xact_cleanup;
walk_entries(journal->entries, cleanup); walk_entries(journal->entries, xact_cleanup);
cleanup.flush(); clear_account_data acct_cleanup;
walk_accounts(journal->master, acct_cleanup);
#endif #endif
TIMER_STOP(report_gen); TIMER_STOP(report_gen);

View file

@ -1,4 +1,5 @@
#include "valexpr.h" #include "valexpr.h"
#include "walk.h"
#include "format.h" #include "format.h"
#include "error.h" #include "error.h"
#include "datetime.h" #include "datetime.h"
@ -83,8 +84,8 @@ void value_expr_t::compute(value_t& result, const details_t& details,
case AMOUNT: case AMOUNT:
if (details.xact) if (details.xact)
result = details.xact->amount; result = details.xact->amount;
else if (details.account) else if (details.account && ACCT_DATA(details.account))
result = details.account->value; result = ACCT_DATA(details.account)->value;
break; break;
case COST: case COST:
@ -94,37 +95,37 @@ void value_expr_t::compute(value_t& result, const details_t& details,
else else
result = details.xact->amount; result = details.xact->amount;
} }
else if (details.account) { else if (details.account && ACCT_DATA(details.account)) {
result = details.account->value.cost(); result = ACCT_DATA(details.account)->value.cost();
} }
break; break;
case TOTAL: case TOTAL:
if (details.xact) if (details.xact && XACT_DATA(details.xact))
result = details.xact->total; result = XACT_DATA(details.xact)->total;
else if (details.account) else if (details.account && ACCT_DATA(details.account))
result = details.account->total; result = ACCT_DATA(details.account)->total;
break; break;
case COST_TOTAL: case COST_TOTAL:
if (details.xact) if (details.xact && XACT_DATA(details.xact))
result = details.xact->total.cost(); result = XACT_DATA(details.xact)->total.cost();
else if (details.account) else if (details.account && ACCT_DATA(details.account))
result = details.account->total.cost(); result = ACCT_DATA(details.account)->total.cost();
break; break;
case VALUE_EXPR: case VALUE_EXPR:
#ifdef NO_CLEANUP #ifdef DO_CLEANUP
assert(format_t::value_expr);
#else
assert(format_t::value_expr.get()); assert(format_t::value_expr.get());
#else
assert(format_t::value_expr);
#endif #endif
format_t::value_expr->compute(result, details); format_t::value_expr->compute(result, details);
break; break;
case TOTAL_EXPR: case TOTAL_EXPR:
#ifdef NO_CLEANUP #ifdef DO_CLEANUP
assert(format_t::total_expr);
#else
assert(format_t::total_expr.get()); assert(format_t::total_expr.get());
#else
assert(format_t::total_expr);
#endif #endif
format_t::total_expr->compute(result, details); format_t::total_expr->compute(result, details);
break; break;
@ -173,17 +174,17 @@ void value_expr_t::compute(value_t& result, const details_t& details,
break; break;
case INDEX: case INDEX:
if (details.xact) if (details.xact && XACT_DATA(details.xact))
result = details.xact->index + 1; result = XACT_DATA(details.xact)->index + 1;
else if (details.account) else if (details.account && ACCT_DATA(details.account))
result = details.account->subcount; result = ACCT_DATA(details.account)->subcount;
break; break;
case COUNT: case COUNT:
if (details.xact) if (details.xact && XACT_DATA(details.xact))
result = details.xact->index + 1; result = XACT_DATA(details.xact)->index + 1;
else if (details.account) else if (details.account && ACCT_DATA(details.account))
result = details.account->count; result = ACCT_DATA(details.account)->count;
break; break;
case DEPTH: case DEPTH:
@ -194,15 +195,17 @@ void value_expr_t::compute(value_t& result, const details_t& details,
break; break;
case F_ARITH_MEAN: case F_ARITH_MEAN:
if (details.xact) { if (details.xact && XACT_DATA(details.xact)) {
assert(left); assert(left);
left->compute(result, details); 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); assert(left);
left->compute(result, details); left->compute(result, details);
result /= amount_t(details.account->count); result /= amount_t(ACCT_DATA(details.account)->count);
} }
break; break;

157
walk.cc
View file

@ -20,11 +20,14 @@ void sort_transactions::flush()
void calc_transactions::operator()(transaction_t * xact) void calc_transactions::operator()(transaction_t * xact)
{ {
if (last_xact) { if (! xact->data)
xact->total += last_xact->total; xact->data = new transaction_data_t;
xact->index = last_xact->index + 1;
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 { } else {
xact->index = 0; XACT_DATA(xact)->index = 0;
} }
if (inverted) { if (inverted) {
@ -33,8 +36,8 @@ void calc_transactions::operator()(transaction_t * xact)
xact->cost->negate(); xact->cost->negate();
} }
if (! (xact->dflags & TRANSACTION_NO_TOTAL)) if (! (XACT_DATA(xact)->dflags & TRANSACTION_NO_TOTAL))
xact->total += *xact; XACT_DATA(xact)->total += *xact;
(*handler)(xact); (*handler)(xact);
@ -47,6 +50,80 @@ void calc_transactions::operator()(transaction_t * xact)
last_xact = 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() void collapse_transactions::report_cumulative_subtotal()
{ {
if (count == 1) { if (count == 1) {
@ -54,23 +131,12 @@ void collapse_transactions::report_cumulative_subtotal()
} else { } else {
assert(count > 1); 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; value_t result;
format_t::compute_total(result, details_t(totals_account)); format_t::compute_total(result, details_t(totals_account));
handle_value(result, totals_account, last_entry, 0, xact_temps, handler);
#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
} }
subtotal = 0; subtotal = 0;
@ -99,26 +165,17 @@ void changed_value_transactions::operator()(transaction_t * xact)
entry->payee = "Commodities revalued"; entry->payee = "Commodities revalued";
entry->date = current; entry->date = current;
#if 0 handle_value(cur_bal, NULL, entry, TRANSACTION_NO_TOTAL, xact_temps,
for (amounts_map::const_iterator i = diff.amounts.begin(); handler);
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
} }
} }
if (xact) { if (xact) {
if (changed_values_only) if (changed_values_only) {
xact->dflags |= TRANSACTION_DISPLAYED; if (! xact->data)
xact->data = new transaction_data_t;
XACT_DATA(xact)->dflags |= TRANSACTION_DISPLAYED;
}
(*handler)(xact); (*handler)(xact);
} }
@ -151,27 +208,23 @@ void subtotal_transactions::flush(const char * spec_fmt)
for (balances_map::iterator i = balances.begin(); for (balances_map::iterator i = balances.begin();
i != balances.end(); i != balances.end();
i++) { i++) {
value_t result;
entry->date = finish; entry->date = finish;
{
transaction_t temp((*i).first); transaction_t temp((*i).first);
temp.entry = entry; temp.entry = entry;
temp.total = (*i).second; {
value_t result; 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)); format_t::compute_total(result, details_t(&temp));
}
temp.data = NULL;
}
entry->date = start; entry->date = start;
#if 0 handle_value(result, (*i).first, entry, 0, xact_temps, handler);
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);
}
#endif
} }
balances.clear(); balances.clear();

116
walk.h
View file

@ -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> class ignore_transactions : public item_handler<transaction_t>
{ {
public: public:
virtual void operator()(transaction_t * xact) {} 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: public:
virtual void operator()(transaction_t * xact) { 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) {} : item_handler<transaction_t>(handler) {}
virtual void operator()(transaction_t * xact) { virtual void operator()(transaction_t * xact) {
xact->account->value += *xact; if (! ACCT_DATA(xact->account))
xact->account->subcount++; xact->account->data = new account_data_t;
ACCT_DATA(xact->account)->value += *xact;
ACCT_DATA(xact->account)->subcount++;
if (handler) if (handler)
(*handler)(xact); (*handler)(xact);
@ -196,12 +249,21 @@ class collapse_transactions : public item_handler<transaction_t>
} }
virtual ~collapse_transactions() { virtual ~collapse_transactions() {
if (totals_account->data) {
delete (account_data_t *) totals_account->data;
totals_account->data = NULL;
}
delete totals_account; delete totals_account;
for (transactions_deque::iterator i = xact_temps.begin(); for (transactions_deque::iterator i = xact_temps.begin();
i != xact_temps.end(); i != xact_temps.end();
i++) i++) {
if ((*i)->data) {
delete (transaction_data_t *) (*i)->data;
(*i)->data = NULL;
}
delete *i; delete *i;
} }
}
virtual void flush() { virtual void flush() {
if (subtotal) if (subtotal)
@ -250,9 +312,14 @@ class changed_value_transactions : public item_handler<transaction_t>
for (transactions_deque::iterator i = xact_temps.begin(); for (transactions_deque::iterator i = xact_temps.begin();
i != xact_temps.end(); i != xact_temps.end();
i++) i++) {
if ((*i)->data) {
delete (transaction_data_t *) (*i)->data;
(*i)->data = NULL;
}
delete *i; delete *i;
} }
}
virtual void flush() { virtual void flush() {
(*this)(NULL); (*this)(NULL);
@ -286,9 +353,14 @@ class subtotal_transactions : public item_handler<transaction_t>
for (transactions_deque::iterator i = xact_temps.begin(); for (transactions_deque::iterator i = xact_temps.begin();
i != xact_temps.end(); i != xact_temps.end();
i++) i++) {
if ((*i)->data) {
delete (transaction_data_t *) (*i)->data;
(*i)->data = NULL;
}
delete *i; delete *i;
} }
}
void flush(const char * spec_fmt); 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(); for (transactions_list::iterator i = xact->entry->transactions.begin();
i != xact->entry->transactions.end(); i != xact->entry->transactions.end();
i++) i++)
if (! ((*i)->dflags & TRANSACTION_HANDLED) && if ((! (*i)->data ||
! (XACT_DATA(*i)->dflags & TRANSACTION_HANDLED)) &&
(*i == xact ? also_matching : (*i == xact ? also_matching :
! ((*i)->flags & TRANSACTION_AUTO))) { ! ((*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); (*handler)(*i);
} }
} }
@ -363,16 +438,31 @@ class related_transactions : public item_handler<transaction_t>
// Account walking functions // 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) { inline void sum_accounts(account_t * account) {
if (! account->data)
account->data = new account_data_t;
for (accounts_map::iterator i = account->accounts.begin(); for (accounts_map::iterator i = account->accounts.begin();
i != account->accounts.end(); i != account->accounts.end();
i++) { i++) {
sum_accounts((*i).second); sum_accounts((*i).second);
account->total += (*i).second->total; ACCT_DATA(account)->total += ACCT_DATA((*i).second)->total;
account->count += (*i).second->count + (*i).second->subcount; ACCT_DATA(account)->count += (ACCT_DATA((*i).second)->count +
ACCT_DATA((*i).second)->subcount);
} }
account->total += account->value; ACCT_DATA(account)->total += ACCT_DATA(account)->value;
account->count += account->subcount; ACCT_DATA(account)->count += ACCT_DATA(account)->subcount;
} }
typedef std::deque<account_t *> accounts_deque; typedef std::deque<account_t *> accounts_deque;