only compute the cost when it differs from the amount

This commit is contained in:
John Wiegley 2004-08-21 15:55:03 -04:00
parent 225acd14e5
commit 000bfe1cec
18 changed files with 227 additions and 112 deletions

View file

@ -890,8 +890,8 @@ void amount_t::write_quantity(std::ostream& out) const
out.write(&byte, sizeof(byte));
std::size_t size;
mpz_export(buf, &size, 1, sizeof(int), 0, 0, MPZ(quantity));
unsigned short len = size * sizeof(int);
mpz_export(buf, &size, 1, sizeof(short), 0, 0, MPZ(quantity));
unsigned short len = size * sizeof(short);
out.write((char *)&len, sizeof(len));
if (len) {
@ -930,7 +930,7 @@ void amount_t::read_quantity(std::istream& in)
unsigned short len;
in.read((char *)&len, sizeof(len));
in.read(buf, len);
mpz_import(MPZ(quantity), len / sizeof(int), 1, sizeof(int), 0, 0, buf);
mpz_import(MPZ(quantity), len / sizeof(short), 1, sizeof(short), 0, 0, buf);
char negative;
in.read(&negative, sizeof(negative));

View file

@ -21,7 +21,7 @@ void automated_transaction_t::extend_entry(entry_t * entry)
amt = (*t)->amount;
transaction_t * xact
= new transaction_t((*t)->account, amt, amt,
= new transaction_t((*t)->account, amt,
(*t)->flags | TRANSACTION_AUTO);
entry->add_transaction(xact);
}

View file

@ -85,19 +85,35 @@ void balance_t::write(std::ostream& out,
}
balance_pair_t::balance_pair_t(const transaction_t& xact)
: quantity(xact.amount), cost(xact.cost) {}
: quantity(xact.amount), cost(NULL)
{
if (xact.cost)
cost = new balance_t(*xact.cost);
}
balance_pair_t& balance_pair_t::operator+=(const transaction_t& xact)
{
if (xact.cost && ! cost)
cost = new balance_t(quantity);
quantity += xact.amount;
cost += xact.cost;
if (cost)
*cost += xact.cost ? *xact.cost : xact.amount;
return *this;
}
balance_pair_t& balance_pair_t::operator-=(const transaction_t& xact)
{
if (xact.cost && ! cost)
cost = new balance_t(quantity);
quantity -= xact.amount;
cost -= xact.cost;
if (cost)
*cost -= xact.cost ? *xact.cost : xact.amount;
return *this;
}

133
balance.h
View file

@ -387,93 +387,146 @@ class balance_pair_t
{
public:
balance_t quantity;
balance_t cost;
balance_t * cost;
bool valid() const {
return quantity.valid() && cost.valid();
return quantity.valid() && (! cost || cost->valid());
}
// constructors
balance_pair_t() {}
balance_pair_t() : cost(NULL) {}
balance_pair_t(const balance_pair_t& bal_pair)
: quantity(bal_pair.quantity), cost(bal_pair.cost) {}
: quantity(bal_pair.quantity), cost(NULL) {
if (bal_pair.cost)
cost = new balance_t(*bal_pair.cost);
}
#if 0
balance_pair_t(const balance_t& _quantity, const balance_t& _cost)
: quantity(_quantity), cost(_cost) {}
#endif
balance_pair_t(const balance_t& _quantity)
: quantity(_quantity), cost(_quantity) {}
: quantity(_quantity), cost(NULL) {}
#if 0
balance_pair_t(const amount_t& _quantity, const amount_t& _cost)
: quantity(_quantity), cost(_cost) {}
#endif
balance_pair_t(const amount_t& _quantity)
: quantity(_quantity), cost(_quantity) {}
: quantity(_quantity), cost(NULL) {}
balance_pair_t(const int value)
: quantity(value), cost(value) {}
: quantity(value), cost(NULL) {}
balance_pair_t(const unsigned int value)
: quantity(value), cost(value) {}
: quantity(value), cost(NULL) {}
balance_pair_t(const double value)
: quantity(value), cost(value) {}
: quantity(value), cost(NULL) {}
balance_pair_t(const transaction_t& xact);
// destructor
~balance_pair_t() {}
~balance_pair_t() {
if (cost)
delete cost;
}
// assignment operator
balance_pair_t& operator=(const balance_pair_t& bal_pair) {
if (cost) {
delete cost;
cost = NULL;
}
quantity = bal_pair.quantity;
cost = bal_pair.cost;
if (bal_pair.cost)
cost = new balance_t(*bal_pair.cost);
return *this;
}
balance_pair_t& operator=(const balance_t& bal) {
quantity = cost = bal;
if (cost) {
delete cost;
cost = NULL;
}
quantity = bal;
return *this;
}
balance_pair_t& operator=(const amount_t& amt) {
quantity = cost = amt;
if (cost) {
delete cost;
cost = NULL;
}
quantity = amt;
return *this;
}
balance_pair_t& operator=(const int value) {
quantity = cost = amount_t(value);
if (cost) {
delete cost;
cost = NULL;
}
quantity = value;
return *this;
}
balance_pair_t& operator=(const unsigned int value) {
quantity = cost = amount_t(value);
if (cost) {
delete cost;
cost = NULL;
}
quantity = value;
return *this;
}
balance_pair_t& operator=(const double value) {
quantity = cost = amount_t(value);
if (cost) {
delete cost;
cost = NULL;
}
quantity = value;
return *this;
}
// in-place arithmetic
balance_pair_t& operator+=(const balance_pair_t& bal_pair) {
if (bal_pair.cost && ! cost)
cost = new balance_t(quantity);
quantity += bal_pair.quantity;
cost += bal_pair.cost;
if (cost)
*cost += bal_pair.cost ? *bal_pair.cost : bal_pair.quantity;
return *this;
}
balance_pair_t& operator+=(const balance_t& bal) {
quantity += bal;
cost += bal;
if (cost)
*cost += bal;
return *this;
}
balance_pair_t& operator+=(const amount_t& amt) {
quantity += amt;
cost += amt;
if (cost)
*cost += amt;
return *this;
}
balance_pair_t& operator+=(const transaction_t& xact);
balance_pair_t& operator-=(const balance_pair_t& bal_pair) {
if (bal_pair.cost && ! cost)
cost = new balance_t(quantity);
quantity -= bal_pair.quantity;
cost -= bal_pair.cost;
if (cost)
*cost -= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity;
return *this;
}
balance_pair_t& operator-=(const balance_t& bal) {
quantity -= bal;
cost -= bal;
if (cost)
*cost -= bal;
return *this;
}
balance_pair_t& operator-=(const amount_t& amt) {
quantity -= amt;
cost -= amt;
if (cost)
*cost -= amt;
return *this;
}
balance_pair_t& operator-=(const transaction_t& xact);
@ -513,34 +566,50 @@ class balance_pair_t
// multiplication and division
balance_pair_t& operator*=(const balance_pair_t& bal_pair) {
if (bal_pair.cost && ! cost)
cost = new balance_t(quantity);
quantity *= bal_pair.quantity;
cost *= bal_pair.quantity;
if (cost)
*cost *= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity;
return *this;
}
balance_pair_t& operator*=(const balance_t& bal) {
quantity *= bal;
cost *= bal;
if (cost)
*cost *= bal;
return *this;
}
balance_pair_t& operator*=(const amount_t& amt) {
quantity *= amt;
cost *= amt;
if (cost)
*cost *= amt;
return *this;
}
balance_pair_t& operator/=(const balance_pair_t& bal_pair) {
if (bal_pair.cost && ! cost)
cost = new balance_t(quantity);
quantity /= bal_pair.quantity;
cost /= bal_pair.quantity;
if (cost)
*cost /= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity;
return *this;
}
balance_pair_t& operator/=(const balance_t& bal) {
quantity /= bal;
cost /= bal;
if (cost)
*cost /= bal;
return *this;
}
balance_pair_t& operator/=(const amount_t& amt) {
quantity /= amt;
cost /= amt;
if (cost)
*cost /= amt;
return *this;
}
@ -637,7 +706,8 @@ class balance_pair_t
// unary negation
balance_pair_t& negate() {
quantity.negate();
cost.negate();
if (cost)
cost->negate();
return *this;
}
balance_pair_t negated() const {
@ -658,7 +728,10 @@ class balance_pair_t
inline balance_pair_t abs(const balance_pair_t& bal_pair) {
balance_pair_t temp;
temp.quantity = abs(bal_pair.quantity);
temp.cost = abs(bal_pair.cost);
if (bal_pair.cost) {
temp.cost = new balance_t;
*temp.cost = abs(*bal_pair.cost);
}
return temp;
}

View file

@ -9,7 +9,7 @@
namespace ledger {
const unsigned long binary_magic_number = 0xFFEED765;
static const unsigned long format_version = 0x0002000e;
static const unsigned long format_version = 0x00020010;
bool binary_parser_t::test(std::istream& in) const
{
@ -102,7 +102,10 @@ transaction_t * read_binary_transaction(std::istream& in, entry_t * entry)
xact->account->add_transaction(xact);
read_binary_amount(in, xact->amount);
read_binary_amount(in, xact->cost);
if (read_binary_number<char>(in) == 1) {
xact->cost = new amount_t;
read_binary_amount(in, *xact->cost);
}
read_binary_number(in, xact->flags);
read_binary_string(in, xact->note);
@ -314,7 +317,12 @@ void write_binary_transaction(std::ostream& out, transaction_t * xact)
{
write_binary_number(out, xact->account->ident);
write_binary_amount(out, xact->amount);
write_binary_amount(out, xact->cost);
if (xact->cost) {
write_binary_number<char>(out, 1);
write_binary_amount(out, *xact->cost);
} else {
write_binary_number<char>(out, 0);
}
write_binary_number(out, xact->flags);
write_binary_string(out, xact->note);
}

View file

@ -180,7 +180,7 @@ OPT_BEGIN(end_date, "e:") {
OPT_BEGIN(current, "c") {
if (! config->predicate.empty())
config->predicate += "&";
config->predicate += "d<=N";
config->predicate += "d<=m";
} OPT_END(current);
OPT_BEGIN(cleared, "C") {
@ -346,7 +346,7 @@ OPT_BEGIN(trend, "X") {
OPT_BEGIN(weighted_trend, "Z") {
config->value_expr = "a";
config->total_expr
= "MD(MO/(1+(((N-d)/(30*86400))<0?0:((N-d)/(30*86400)))))";
= "MD(MO/(1+(((m-d)/(30*86400))<0?0:((m-d)/(30*86400)))))";
} OPT_END(weighted_trend);
} // namespace ledger

View file

@ -289,8 +289,8 @@ void format_t::format_elements(std::ostream& out,
std::string disp;
bool use_disp = false;
if (details.xact->amount != details.xact->cost) {
amount_t unit_cost = details.xact->cost / details.xact->amount;
if (details.xact->cost) {
amount_t unit_cost = *details.xact->cost / details.xact->amount;
std::ostringstream stream;
stream << details.xact->amount << " @ " << unit_cost;
disp = stream.str();

View file

@ -240,7 +240,8 @@ static void dataHandler(void *userData, const char *s, int len)
curr_value = value;
xact->amount = value;
xact->cost = curr_value;
if (value != curr_value)
xact->cost = new amount_t(curr_value);
break;
}

View file

@ -30,9 +30,10 @@ bool journal_t::add_entry(entry_t * entry)
i++) {
(*i)->account->add_transaction(*i);
if ((*i)->amount != (*i)->cost) {
assert((*i)->amount.commodity);
(*i)->amount.commodity->add_price(entry->date, (*i)->cost / (*i)->amount);
if ((*i)->cost) {
assert((*i)->cost->commodity);
(*i)->amount.commodity->add_price(entry->date,
*(*i)->cost / (*i)->amount);
}
}
@ -98,17 +99,15 @@ entry_t * journal_t::derive_entry(strings_list::iterator i,
m_xact = matching->transactions.front();
amount_t amt(*i++);
first = xact = new transaction_t(m_xact->account, amt, amt);
first = xact = new transaction_t(m_xact->account, amt);
added->add_transaction(xact);
if (xact->amount.commodity->symbol.empty()) {
if (xact->amount.commodity->symbol.empty())
xact->amount.commodity = m_xact->amount.commodity;
xact->cost.commodity = m_xact->amount.commodity;
}
m_xact = matching->transactions.back();
xact = new transaction_t(m_xact->account, - first->amount, - first->amount);
xact = new transaction_t(m_xact->account, - first->amount);
added->add_transaction(xact);
if (i != end && std::string(*i++) == "-from" && i != end)
@ -149,7 +148,7 @@ entry_t * journal_t::derive_entry(strings_list::iterator i,
}
amount_t amt(*i++);
transaction_t * xact = new transaction_t(acct, amt, amt);
transaction_t * xact = new transaction_t(acct, amt);
added->add_transaction(xact);
if (! xact->amount.commodity)

View file

@ -49,7 +49,7 @@ class transaction_t
entry_t * entry;
account_t * account;
amount_t amount;
amount_t cost;
amount_t * cost;
unsigned short flags;
std::string note;
@ -58,16 +58,20 @@ class transaction_t
mutable unsigned short dflags;
transaction_t(account_t * _account)
: entry(NULL), account(_account), flags(TRANSACTION_NORMAL),
index(0), dflags(0) {}
: entry(NULL), account(_account), cost(NULL),
flags(TRANSACTION_NORMAL), index(0), dflags(0) {}
transaction_t(account_t * _account,
const amount_t& _amount,
const amount_t& _cost,
unsigned int _flags = TRANSACTION_NORMAL,
const std::string& _note = "")
: entry(NULL), account(_account), amount(_amount),
cost(_cost), flags(_flags), note(_note), index(0), dflags(0) {}
cost(NULL), flags(_flags), note(_note), index(0), dflags(0) {}
~transaction_t() {
if (cost)
delete cost;
}
};
@ -127,18 +131,19 @@ class account_t
mutable balance_pair_t value;
mutable balance_pair_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;
static ident_t next_ident;
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),
count(0), dflags(0) {}
count(0), subcount(0), dflags(0) {}
~account_t();

View file

@ -490,8 +490,8 @@ register report, @samp{-T} changes the totals column; in a balance
report, this is the value given for each account. If @samp{-T} was
not specified, the current report style's value expression is used.
@item N
This is always the present date.
@item m
This is always the present moment/date.
@end table
@subsubsection Transaction/account details
@ -522,7 +522,7 @@ it's depth is one.
@item n
The index of a transaction, or the count of transactions affecting an
account (including children).
account.
@item X
1, if a transaction's entry has been cleared, 0 otherwise.
@ -538,6 +538,10 @@ account (including children).
The total of all transactions seen so far, or the total of an account
and all its children.
@item N
The total count of transactions affecting an account and all its
children.
@item C
The total cost of all transactions seen so far; the total cost of an
account and all its children.

3
qif.cc
View file

@ -99,7 +99,6 @@ unsigned int qif_parser_t::parse(std::istream& in,
xact->amount.commodity = def_commodity;
if (c == '$')
xact->amount.negate();
xact->cost = xact->amount;
break;
case 'C':
@ -164,7 +163,7 @@ unsigned int qif_parser_t::parse(std::istream& in,
misc = journal->find_account("Miscellaneous");
transaction_t * nxact = new transaction_t(misc);
entry->add_transaction(nxact);
nxact->amount = nxact->cost = - xact->amount;
nxact->amount.negate();
}
if (journal->add_entry(entry.release()))

View file

@ -1,16 +0,0 @@
#!/usr/bin/python
import sys
import re
print_total = 0
def clean(num):
return float(re.sub("(\s+|\$|,)","",num))
for line in sys.stdin:
print line[:10],
if print_total:
print clean(line[68:80])
else:
print clean(line[55:67])

View file

@ -73,15 +73,13 @@ transaction_t * parse_transaction_text(char * line, account_t * account,
char * price_str = std::strchr(cost_str, '@');
if (price_str) {
*price_str++ = '\0';
xact->cost.parse(price_str);
xact->cost = new amount_t;
xact->cost->parse(price_str);
}
xact->amount.parse(cost_str);
if (price_str)
xact->cost *= xact->amount;
else
xact->cost = xact->amount;
*xact->cost *= xact->amount;
}
if (*p == '[' || *p == '(') {
@ -99,8 +97,8 @@ transaction_t * parse_transaction_text(char * line, account_t * account,
if (! xact->amount.commodity)
xact->amount.commodity = commodity_t::null_commodity;
if (! xact->cost.commodity)
xact->cost.commodity = commodity_t::null_commodity;
if (xact->cost && ! xact->cost->commodity)
xact->cost->commodity = commodity_t::null_commodity;
return xact.release();
}
@ -156,8 +154,8 @@ bool finalize_entry(entry_t * entry)
if (! ((*x)->flags & TRANSACTION_VIRTUAL) ||
((*x)->flags & TRANSACTION_BALANCE)) {
DEBUG_PRINT("ledger.textual.finalize",
"item cost is " << (*x)->cost);
balance += (*x)->cost;
"item cost is " << ((*x)->cost ? *(*x)->cost : (*x)->amount));
balance += (*x)->cost ? *(*x)->cost : (*x)->amount;
}
// If one transaction of a two-line transaction is of a different
@ -169,7 +167,7 @@ bool finalize_entry(entry_t * entry)
for (transactions_list::const_iterator x = entry->transactions.begin();
x != entry->transactions.end();
x++) {
if ((*x)->cost != (*x)->amount || ((*x)->flags & TRANSACTION_VIRTUAL))
if ((*x)->cost || ((*x)->flags & TRANSACTION_VIRTUAL))
continue;
for (amounts_map::const_iterator i = balance.amounts.begin();
@ -177,9 +175,10 @@ bool finalize_entry(entry_t * entry)
i++)
if ((*i).second.commodity != (*x)->amount.commodity) {
assert((*x)->amount);
balance -= (*x)->cost;
(*x)->cost = - (*i).second;
balance += (*x)->cost;
balance -= (*x)->amount;
assert(! (*x)->cost);
(*x)->cost = new amount_t(- (*i).second);
balance += *(*x)->cost;
break;
}
@ -208,7 +207,7 @@ bool finalize_entry(entry_t * entry)
// inverse of the computed value of the others.
amounts_map::const_iterator i = balance.amounts.begin();
(*x)->amount = (*x)->cost = - balance.amount((*i).first);
(*x)->amount = - balance.amount((*i).first);
balance = 0;
}
@ -401,7 +400,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
time_commodity = amt.commodity;
transaction_t * xact
= new transaction_t(last_account, amt, amt, TRANSACTION_VIRTUAL);
= new transaction_t(last_account, amt, TRANSACTION_VIRTUAL);
curr->add_transaction(xact);
if (! finalize_entry(curr.get()) ||

View file

@ -83,10 +83,18 @@ void value_expr_t::compute(value_t& result, const details_t& details,
break;
case COST:
if (details.xact)
result = details.xact->cost;
else if (details.account)
result = details.account->value.cost;
if (details.xact) {
if (details.xact->cost)
result = *details.xact->cost;
else
result = details.xact->amount;
}
else if (details.account) {
if (details.account->value.cost)
result = *details.account->value.cost;
else
result = details.account->value.quantity;
}
break;
case TOTAL:
@ -96,10 +104,18 @@ void value_expr_t::compute(value_t& result, const details_t& details,
result = details.account->total.quantity;
break;
case COST_TOTAL:
if (details.xact)
result = details.xact->total.cost;
else if (details.account)
result = details.account->total.cost;
if (details.xact) {
if (details.xact->total.cost)
result = *details.xact->total.cost;
else
result = details.xact->total.quantity;
}
else if (details.account) {
if (details.account->total.cost)
result = *details.account->total.cost;
else
result = details.account->total.quantity;
}
break;
case VALUE_EXPR:
@ -163,6 +179,13 @@ 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;
break;
case COUNT:
if (details.xact)
result = details.xact->index + 1;
else if (details.account)
@ -377,7 +400,7 @@ value_expr_t * parse_value_term(std::istream& in)
in.get(c);
switch (c) {
// Basic terms
case 'N':
case 'm':
node.reset(new value_expr_t(value_expr_t::CONSTANT_T));
node->constant_t = now;
break;
@ -388,6 +411,7 @@ value_expr_t * parse_value_term(std::istream& in)
case 'X': node.reset(new value_expr_t(value_expr_t::CLEARED)); break;
case 'R': node.reset(new value_expr_t(value_expr_t::REAL)); break;
case 'n': node.reset(new value_expr_t(value_expr_t::INDEX)); break;
case 'N': node.reset(new value_expr_t(value_expr_t::COUNT)); break;
case 'l': node.reset(new value_expr_t(value_expr_t::DEPTH)); break;
case 'O': node.reset(new value_expr_t(value_expr_t::TOTAL)); break;
case 'C': node.reset(new value_expr_t(value_expr_t::COST_TOTAL)); break;
@ -715,6 +739,7 @@ void dump_value_expr(std::ostream& out, const value_expr_t * node)
case value_expr_t::CLEARED: out << "CLEARED"; break;
case value_expr_t::REAL: out << "REAL"; break;
case value_expr_t::INDEX: out << "INDEX"; break;
case value_expr_t::COUNT: out << "COUNT"; break;
case value_expr_t::DEPTH: out << "DEPTH"; break;
case value_expr_t::TOTAL: out << "TOTAL"; break;
case value_expr_t::COST_TOTAL: out << "COST_TOTAL"; break;

View file

@ -57,6 +57,7 @@ struct value_expr_t
DEPTH,
// Item totals
COUNT,
TOTAL,
COST_TOTAL,

View file

@ -29,7 +29,8 @@ void calc_transactions::operator()(transaction_t * xact)
if (inverted) {
xact->amount.negate();
xact->cost.negate();
if (xact->cost)
xact->cost->negate();
}
if (! (xact->dflags & TRANSACTION_NO_TOTAL))
@ -39,7 +40,8 @@ void calc_transactions::operator()(transaction_t * xact)
if (inverted) {
xact->amount.negate();
xact->cost.negate();
if (xact->cost)
xact->cost->negate();
}
last_xact = xact;
@ -64,7 +66,6 @@ void collapse_transactions::report_cumulative_subtotal()
total_xact->entry = last_entry;
total_xact->amount = (*i).second;
total_xact->cost = (*i).second;
(*handler)(total_xact);
}
@ -161,7 +162,6 @@ void subtotal_transactions::flush(const char * spec_fmt)
xact->entry = entry;
xact->amount = (*j).second;
xact->cost = (*j).second;
(*handler)(xact);
}

5
walk.h
View file

@ -121,7 +121,7 @@ class set_account_value : public item_handler<transaction_t>
virtual void operator()(transaction_t * xact) {
xact->account->value += *xact;
xact->account->count++;
xact->account->subcount++;
if (handler)
(*handler)(xact);
@ -364,9 +364,10 @@ inline void sum_accounts(account_t * account) {
i++) {
sum_accounts((*i).second);
account->total += (*i).second->total;
account->count += (*i).second->count;
account->count += (*i).second->count + (*i).second->subcount;
}
account->total += account->value;
account->count += account->subcount;
}
typedef std::deque<account_t *> accounts_deque;