Began support for improved commodity handling.

This commit is contained in:
John Wiegley 2006-03-03 10:40:44 +00:00
parent 96d6d62ad9
commit 2ebfddf401
12 changed files with 152 additions and 133 deletions

View file

@ -1279,14 +1279,13 @@ void amount_t::annotate_commodity(const amount_t& price,
DEBUG_PRINT("amounts.commodities", " Annotated amount is " << *this); DEBUG_PRINT("amounts.commodities", " Annotated amount is " << *this);
} }
void amount_t::reduce_commodity(const bool keep_price, amount_t amount_t::reduce_commodity(const bool keep_price,
const bool keep_date, const bool keep_date,
const bool keep_tag) const bool keep_tag) const
{ {
if (! commodity().annotated) if (! commodity().annotated ||
return; (keep_price && keep_date && keep_tag))
if (keep_price && keep_date && keep_tag) return *this;
return;
DEBUG_PRINT("amounts.commodities", "Reducing commodity for amount " DEBUG_PRINT("amounts.commodities", "Reducing commodity for amount "
<< *this << std::endl << *this << std::endl
@ -1297,16 +1296,27 @@ void amount_t::reduce_commodity(const bool keep_price,
annotated_commodity_t& annotated_commodity_t&
ann_comm(static_cast<annotated_commodity_t&>(commodity())); ann_comm(static_cast<annotated_commodity_t&>(commodity()));
annotated_commodity_t * new_ann_comm = commodity_t * new_comm;
annotated_commodity_t::find_or_create(*ann_comm.base,
keep_price ?
ann_comm.price : amount_t(),
keep_date ? ann_comm.date : 0,
keep_tag ? ann_comm.tag : "");
assert(new_ann_comm);
set_commodity(*new_ann_comm);
DEBUG_PRINT("amounts.commodities", " Reduced amount is " << *this); if ((keep_price && ann_comm.price) ||
(keep_date && ann_comm.date) ||
(keep_tag && ! ann_comm.tag.empty()))
{
new_comm = annotated_commodity_t::find_or_create
(*ann_comm.base, keep_price ? ann_comm.price : amount_t(),
keep_date ? ann_comm.date : 0, keep_tag ? ann_comm.tag : "");
} else {
new_comm = commodity_t::find_or_create(ann_comm.base_symbol());
}
assert(new_comm);
amount_t temp(*this);
temp.set_commodity(*new_comm);
DEBUG_PRINT("amounts.commodities", " Reduced amount is " << temp);
return temp;
} }
@ -1347,6 +1357,22 @@ bool commodity_t::needs_quotes(const std::string& symbol)
return false; return false;
} }
bool commodity_t::valid() const
{
if (symbol().empty() && this != null_commodity)
return false;
#if 0
if (annotated && ! base)
return false;
#endif
if (precision() > 16)
return false;
return true;
}
commodity_t * commodity_t::create(const std::string& symbol) commodity_t * commodity_t::create(const std::string& symbol)
{ {
std::auto_ptr<commodity_t> commodity(new commodity_t); std::auto_ptr<commodity_t> commodity(new commodity_t);
@ -1497,8 +1523,11 @@ annotated_commodity_t::create(const commodity_t& comm,
commodity->price = price; commodity->price = price;
commodity->date = date; commodity->date = date;
commodity->tag = tag; commodity->tag = tag;
commodity->base = &comm; commodity->base = &comm;
assert(commodity->base);
commodity->ptr = comm.ptr; commodity->ptr = comm.ptr;
assert(commodity->ptr);
commodity->qualified_symbol = comm.symbol(); commodity->qualified_symbol = comm.symbol();

View file

@ -75,9 +75,9 @@ class amount_t
void annotate_commodity(const amount_t& price, void annotate_commodity(const amount_t& price,
const std::time_t date = 0, const std::time_t date = 0,
const std::string& tag = ""); const std::string& tag = "");
void reduce_commodity(const bool keep_price = false, amount_t reduce_commodity(const bool keep_price = false,
const bool keep_date = false, const bool keep_date = false,
const bool keep_tag = false); const bool keep_tag = false) const;
void clear_commodity() { void clear_commodity() {
commodity_ = NULL; commodity_ = NULL;
} }
@ -282,9 +282,6 @@ inline amount_t abs(const amount_t& amt) {
return amt < 0 ? amt.negated() : amt; return amt < 0 ? amt.negated() : amt;
} }
#define base_amount(amt) \
((! show_lots && amt.commodity().price) ? amt.base() : amt)
std::ostream& operator<<(std::ostream& out, const amount_t& amt); std::ostream& operator<<(std::ostream& out, const amount_t& amt);
inline std::istream& operator>>(std::istream& in, amount_t& amt) { inline std::istream& operator>>(std::istream& in, amount_t& amt) {
@ -499,15 +496,7 @@ class commodity_t
return ptr->value(moment); return ptr->value(moment);
} }
bool valid() const { bool valid() const;
if (symbol().empty() && this != null_commodity)
return false;
if (precision() > 16)
return false;
return true;
}
}; };
class annotated_commodity_t : public commodity_t class annotated_commodity_t : public commodity_t

View file

@ -46,6 +46,19 @@ balance_t balance_t::price() const
return temp; return temp;
} }
balance_t balance_t::reduce(const bool keep_price, const bool keep_date,
const bool keep_tag) const
{
balance_t temp;
for (amounts_map::const_iterator i = amounts.begin();
i != amounts.end();
i++)
temp += (*i).second.reduce_commodity(keep_price, keep_date, keep_tag);
return temp;
}
struct compare_amount_commodities { struct compare_amount_commodities {
bool operator()(const amount_t * left, const amount_t * right) const { bool operator()(const amount_t * left, const amount_t * right) const {
return left->commodity().symbol() < right->commodity().symbol(); return left->commodity().symbol() < right->commodity().symbol();
@ -160,14 +173,10 @@ balance_pair_t& balance_pair_t::operator/=(const balance_pair_t& bal_pair)
quantity /= bal_pair.quantity; quantity /= bal_pair.quantity;
if (cost) if (cost)
*cost /= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity; *cost /= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity;
if (bal_pair.price && *bal_pair.price && price)
*price /= *bal_pair.price;
return *this; return *this;
} }
balance_pair_t& balance_pair_t::add(const amount_t& amount, balance_pair_t& balance_pair_t::add(const amount_t& amount,
const amount_t * a_price,
const amount_t * a_cost) const amount_t * a_cost)
{ {
if (a_cost && ! cost) if (a_cost && ! cost)
@ -175,13 +184,6 @@ balance_pair_t& balance_pair_t::add(const amount_t& amount,
quantity += amount; quantity += amount;
if (cost) if (cost)
*cost += a_cost ? *a_cost : amount; *cost += a_cost ? *a_cost : amount;
if (a_price) {
if (! price)
price = new balance_t(*a_price);
else
*price += *a_price;
}
return *this; return *this;
} }
@ -290,8 +292,10 @@ void export_balance()
.def("negate", &balance_t::negate) .def("negate", &balance_t::negate)
.def("amount", &balance_t::amount) .def("amount", &balance_t::amount)
.def("value", &balance_t::value) .def("value", &balance_t::value)
.def("price", &balance_t::price)
.def("reduce", &balance_t::reduce)
.def("write", &balance_t::write) .def("write", &balance_t::write)
.def("valid", &balance_t::valid) .def("valid", &balance_t::valid)
; ;
class_< balance_pair_t > ("BalancePair") class_< balance_pair_t > ("BalancePair")
@ -368,9 +372,6 @@ void export_balance()
.def("__len__", balance_pair_len) .def("__len__", balance_pair_len)
.def("__getitem__", balance_pair_getitem) .def("__getitem__", balance_pair_getitem)
.add_property("price",
make_getter(&balance_pair_t::price,
return_value_policy<reference_existing_object>()))
.add_property("cost", .add_property("cost",
make_getter(&balance_pair_t::cost, make_getter(&balance_pair_t::cost,
return_value_policy<reference_existing_object>())) return_value_policy<reference_existing_object>()))

View file

@ -411,6 +411,9 @@ class balance_t
amount_t amount(const commodity_t& commodity) const; amount_t amount(const commodity_t& commodity) const;
balance_t value(const std::time_t moment) const; balance_t value(const std::time_t moment) const;
balance_t price() const; balance_t price() const;
balance_t reduce(const bool keep_price = false,
const bool keep_date = false,
const bool keep_tag = false) const;
void write(std::ostream& out, const int first_width, void write(std::ostream& out, const int first_width,
const int latter_width = -1) const; const int latter_width = -1) const;
@ -446,56 +449,42 @@ class balance_pair_t
{ {
public: public:
balance_t quantity; balance_t quantity;
balance_t * price;
balance_t * cost; balance_t * cost;
// constructors // constructors
balance_pair_t() : price(NULL), cost(NULL) {} balance_pair_t() : cost(NULL) {}
balance_pair_t(const balance_pair_t& bal_pair) balance_pair_t(const balance_pair_t& bal_pair)
: quantity(bal_pair.quantity), price(NULL), cost(NULL) { : quantity(bal_pair.quantity), cost(NULL) {
if (bal_pair.price)
price = new balance_t(*bal_pair.price);
if (bal_pair.cost) if (bal_pair.cost)
cost = new balance_t(*bal_pair.cost); cost = new balance_t(*bal_pair.cost);
} }
balance_pair_t(const balance_t& _quantity) balance_pair_t(const balance_t& _quantity)
: quantity(_quantity), price(NULL), cost(NULL) {} : quantity(_quantity), cost(NULL) {}
balance_pair_t(const amount_t& _quantity) balance_pair_t(const amount_t& _quantity)
: quantity(_quantity), price(NULL), cost(NULL) {} : quantity(_quantity), cost(NULL) {}
template <typename T> template <typename T>
balance_pair_t(T value) : quantity(value), price(NULL), cost(NULL) {} balance_pair_t(T value) : quantity(value), cost(NULL) {}
// destructor // destructor
~balance_pair_t() { ~balance_pair_t() {
if (price) delete price; if (cost) delete cost;
if (cost) delete cost;
} }
// assignment operator // assignment operator
balance_pair_t& operator=(const balance_pair_t& bal_pair) { balance_pair_t& operator=(const balance_pair_t& bal_pair) {
if (this != &bal_pair) { if (this != &bal_pair) {
if (price) {
delete price;
price = NULL;
}
if (cost) { if (cost) {
delete cost; delete cost;
cost = NULL; cost = NULL;
} }
quantity = bal_pair.quantity; quantity = bal_pair.quantity;
if (bal_pair.price)
price = new balance_t(*bal_pair.price);
if (bal_pair.cost) if (bal_pair.cost)
cost = new balance_t(*bal_pair.cost); cost = new balance_t(*bal_pair.cost);
} }
return *this; return *this;
} }
balance_pair_t& operator=(const balance_t& bal) { balance_pair_t& operator=(const balance_t& bal) {
if (price) {
delete price;
price = NULL;
}
if (cost) { if (cost) {
delete cost; delete cost;
cost = NULL; cost = NULL;
@ -504,10 +493,6 @@ class balance_pair_t
return *this; return *this;
} }
balance_pair_t& operator=(const amount_t& amt) { balance_pair_t& operator=(const amount_t& amt) {
if (price) {
delete price;
price = NULL;
}
if (cost) { if (cost) {
delete cost; delete cost;
cost = NULL; cost = NULL;
@ -517,10 +502,6 @@ class balance_pair_t
} }
template <typename T> template <typename T>
balance_pair_t& operator=(T value) { balance_pair_t& operator=(T value) {
if (price) {
delete price;
price = NULL;
}
if (cost) { if (cost) {
delete cost; delete cost;
cost = NULL; cost = NULL;
@ -536,13 +517,6 @@ class balance_pair_t
quantity += bal_pair.quantity; quantity += bal_pair.quantity;
if (cost) if (cost)
*cost += bal_pair.cost ? *bal_pair.cost : bal_pair.quantity; *cost += bal_pair.cost ? *bal_pair.cost : bal_pair.quantity;
if (bal_pair.price) {
if (! price)
price = new balance_t(*bal_pair.price);
else
*price += *bal_pair.price;
}
return *this; return *this;
} }
balance_pair_t& operator+=(const balance_t& bal) { balance_pair_t& operator+=(const balance_t& bal) {
@ -568,15 +542,6 @@ class balance_pair_t
quantity -= bal_pair.quantity; quantity -= bal_pair.quantity;
if (cost) if (cost)
*cost -= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity; *cost -= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity;
if (bal_pair.price) {
if (! price) {
price = new balance_t(*bal_pair.price);
price->negate();
} else {
*price -= *bal_pair.price;
}
}
return *this; return *this;
} }
balance_pair_t& operator-=(const balance_t& bal) { balance_pair_t& operator-=(const balance_t& bal) {
@ -648,15 +613,6 @@ class balance_pair_t
quantity *= bal_pair.quantity; quantity *= bal_pair.quantity;
if (cost) if (cost)
*cost *= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity; *cost *= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity;
if (bal_pair.price && *bal_pair.price) {
if (price)
*price *= *bal_pair.price;
}
else if (price) {
delete price;
price = NULL;
}
return *this; return *this;
} }
balance_pair_t& operator*=(const balance_t& bal) { balance_pair_t& operator*=(const balance_t& bal) {
@ -826,8 +782,7 @@ class balance_pair_t
// unary negation // unary negation
void negate() { void negate() {
quantity.negate(); quantity.negate();
if (price) price->negate(); if (cost) cost->negate();
if (cost) cost->negate();
} }
balance_pair_t negated() const { balance_pair_t negated() const {
balance_pair_t temp = *this; balance_pair_t temp = *this;
@ -851,8 +806,7 @@ class balance_pair_t
void abs() { void abs() {
quantity.abs(); quantity.abs();
if (price) price->abs(); if (cost) cost->abs();
if (cost) cost->abs();
} }
amount_t amount(const commodity_t& commodity) const { amount_t amount(const commodity_t& commodity) const {
@ -867,12 +821,10 @@ class balance_pair_t
} }
balance_pair_t& add(const amount_t& amount, balance_pair_t& add(const amount_t& amount,
const amount_t * a_price = NULL, const amount_t * a_cost = NULL);
const amount_t * a_cost = NULL);
bool valid() { bool valid() {
return (quantity.valid() && return quantity.valid() && (! cost || cost->valid());
(! price || price->valid()) && (! cost || cost->valid()));
} }
void round() { void round() {

View file

@ -780,9 +780,21 @@ OPT_BEGIN(actual, "L") {
} OPT_END(actual); } OPT_END(actual);
OPT_BEGIN(lots, "") { OPT_BEGIN(lots, "") {
show_lots = true; keep_price = keep_date = keep_tag = true;
} OPT_END(lots); } OPT_END(lots);
OPT_BEGIN(lot_prices, "") {
keep_price = true;
} OPT_END(lots_prices);
OPT_BEGIN(lot_dates, "") {
keep_date = true;
} OPT_END(lots_dates);
OPT_BEGIN(lot_tags, "") {
keep_tag = true;
} OPT_END(lots_tags);
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// //
// Output customization // Output customization
@ -1121,6 +1133,9 @@ option_t config_options[CONFIG_OPTIONS_SIZE] = {
{ "init-file", 'i', true, opt_init_file, false }, { "init-file", 'i', true, opt_init_file, false },
{ "input-date-format", '\0', true, opt_input_date_format, false }, { "input-date-format", '\0', true, opt_input_date_format, false },
{ "limit", 'l', true, opt_limit, false }, { "limit", 'l', true, opt_limit, false },
{ "lot-dates", '\0', false, opt_lot_dates, false },
{ "lot-prices", '\0', false, opt_lot_prices, false },
{ "lot-tags", '\0', false, opt_lot_tags, false },
{ "lots", '\0', false, opt_lots, false }, { "lots", '\0', false, opt_lots, false },
{ "market", 'V', false, opt_market, false }, { "market", 'V', false, opt_market, false },
{ "monthly", 'M', false, opt_monthly, false }, { "monthly", 'M', false, opt_monthly, false },

View file

@ -99,7 +99,7 @@ class config_t
std::list<item_handler<transaction_t> *>& ptrs); std::list<item_handler<transaction_t> *>& ptrs);
}; };
#define CONFIG_OPTIONS_SIZE 78 #define CONFIG_OPTIONS_SIZE 81
extern option_t config_options[CONFIG_OPTIONS_SIZE]; extern option_t config_options[CONFIG_OPTIONS_SIZE];
void option_help(std::ostream& out); void option_help(std::ostream& out);

View file

@ -13,6 +13,10 @@ std::auto_ptr<value_calc> total_expr;
std::auto_ptr<scope_t> global_scope; std::auto_ptr<scope_t> global_scope;
std::time_t terminus; std::time_t terminus;
bool keep_price = false;
bool keep_date = false;
bool keep_tag = false;
details_t::details_t(const transaction_t& _xact) details_t::details_t(const transaction_t& _xact)
: entry(_xact.entry), xact(&_xact), account(xact_account(_xact)) : entry(_xact.entry), xact(&_xact), account(xact_account(_xact))
{ {
@ -643,6 +647,9 @@ void value_expr_t::compute(value_t& result, const details_t& details,
assert(0); assert(0);
break; break;
} }
if (! keep_price || ! keep_date || ! keep_tag)
result = result.reduce(keep_price, keep_date, keep_tag);
} }
static inline void unexpected(char c, char wanted = '\0') { static inline void unexpected(char c, char wanted = '\0') {

View file

@ -249,6 +249,10 @@ extern std::auto_ptr<scope_t> global_scope;
extern std::time_t terminus; extern std::time_t terminus;
extern bool initialized; extern bool initialized;
extern bool keep_price;
extern bool keep_date;
extern bool keep_tag;
void init_value_expr(); void init_value_expr();
bool compute_amount(value_expr_t * expr, amount_t& amt, bool compute_amount(value_expr_t * expr, amount_t& amt,

View file

@ -728,16 +728,42 @@ value_t value_t::price() const
switch (type) { switch (type) {
case BOOLEAN: case BOOLEAN:
case INTEGER: case INTEGER:
case AMOUNT:
case BALANCE:
return *this; return *this;
case BALANCE_PAIR: case AMOUNT:
if (((balance_pair_t *) data)->price) return ((amount_t *) data)->price();
return *(((balance_pair_t *) data)->price);
else
return 0L;
case BALANCE:
return ((balance_t *) data)->price();
case BALANCE_PAIR:
return ((balance_pair_t *) data)->quantity.price();
default:
assert(0);
break;
}
assert(0);
return value_t();
}
value_t value_t::reduce(const bool keep_price, const bool keep_date,
const bool keep_tag) const
{
switch (type) {
case BOOLEAN:
case INTEGER:
return *this;
case AMOUNT:
return ((amount_t *) data)->reduce_commodity(keep_price, keep_date,
keep_tag);
case BALANCE:
return ((balance_t *) data)->reduce(keep_price, keep_date, keep_tag);
case BALANCE_PAIR:
return ((balance_pair_t *) data)->quantity.reduce(keep_price, keep_date,
keep_tag);
default: default:
assert(0); assert(0);
break; break;
@ -770,22 +796,21 @@ value_t value_t::cost() const
return value_t(); return value_t();
} }
value_t& value_t::add(const amount_t& amount, value_t& value_t::add(const amount_t& amount, const amount_t * cost)
const amount_t * price, const amount_t * cost)
{ {
switch (type) { switch (type) {
case BOOLEAN: case BOOLEAN:
case INTEGER: case INTEGER:
case AMOUNT: case AMOUNT:
if (price || cost) { if (cost) {
cast(BALANCE_PAIR); cast(BALANCE_PAIR);
return add(amount, price, cost); return add(amount, cost);
} }
else if ((type == AMOUNT && else if ((type == AMOUNT &&
((amount_t *) data)->commodity() != amount.commodity()) || ((amount_t *) data)->commodity() != amount.commodity()) ||
(type != AMOUNT && amount.commodity())) { (type != AMOUNT && amount.commodity())) {
cast(BALANCE); cast(BALANCE);
return add(amount, price, cost); return add(amount, cost);
} }
else if (type != AMOUNT) { else if (type != AMOUNT) {
cast(AMOUNT); cast(AMOUNT);
@ -794,15 +819,15 @@ value_t& value_t::add(const amount_t& amount,
break; break;
case BALANCE: case BALANCE:
if (price || cost) { if (cost) {
cast(BALANCE_PAIR); cast(BALANCE_PAIR);
return add(amount, price, cost); return add(amount, cost);
} }
*((balance_t *) data) += amount; *((balance_t *) data) += amount;
break; break;
case BALANCE_PAIR: case BALANCE_PAIR:
((balance_pair_t *) data)->add(amount, price, cost); ((balance_pair_t *) data)->add(amount, cost);
break; break;
default: default:

View file

@ -145,7 +145,7 @@ class value_t
} }
value_t& operator=(const balance_pair_t& value) { value_t& operator=(const balance_pair_t& value) {
if ((balance_pair_t *) data != &value) { if ((balance_pair_t *) data != &value) {
if (! value.price && ! value.cost) { if (! value.cost) {
return *this = value.quantity; return *this = value.quantity;
} else { } else {
destroy(); destroy();
@ -267,9 +267,10 @@ class value_t
void cast(type_t cast_type); void cast(type_t cast_type);
value_t cost() const; value_t cost() const;
value_t price() const; value_t price() const;
value_t& add(const amount_t& amount, value_t reduce(const bool keep_price = false,
const amount_t * price = NULL, const bool keep_date = false,
const amount_t * cost = NULL); const bool keep_tag = false) const;
value_t& add(const amount_t& amount, const amount_t * cost = NULL);
value_t value(const std::time_t moment) const { value_t value(const std::time_t moment) const {
switch (type) { switch (type) {

View file

@ -7,8 +7,6 @@
namespace ledger { namespace ledger {
bool show_lots = false;
template <> template <>
bool compare_items<transaction_t>::operator()(const transaction_t * left, bool compare_items<transaction_t>::operator()(const transaction_t * left,
const transaction_t * right) const transaction_t * right)
@ -44,7 +42,7 @@ void add_transaction_to(const transaction_t& xact, value_t& value)
transaction_xdata_(xact).dflags & TRANSACTION_COMPOSITE) { transaction_xdata_(xact).dflags & TRANSACTION_COMPOSITE) {
value += transaction_xdata_(xact).composite_amount; value += transaction_xdata_(xact).composite_amount;
} }
else if (xact.cost || xact.amount.commodity().annotated || value) { else if (xact.cost || value) {
value.add(xact.amount, xact.cost); value.add(xact.amount, xact.cost);
} }
else { else {

2
walk.h
View file

@ -120,8 +120,6 @@ inline const account_t * xact_account(const transaction_t& xact) {
return xact_account(const_cast<transaction_t&>(xact)); return xact_account(const_cast<transaction_t&>(xact));
} }
extern bool show_lots;
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
inline void walk_transactions(transactions_list::iterator begin, inline void walk_transactions(transactions_list::iterator begin,