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);
}
void amount_t::reduce_commodity(const bool keep_price,
const bool keep_date,
const bool keep_tag)
amount_t amount_t::reduce_commodity(const bool keep_price,
const bool keep_date,
const bool keep_tag) const
{
if (! commodity().annotated)
return;
if (keep_price && keep_date && keep_tag)
return;
if (! commodity().annotated ||
(keep_price && keep_date && keep_tag))
return *this;
DEBUG_PRINT("amounts.commodities", "Reducing commodity for amount "
<< *this << std::endl
@ -1297,16 +1296,27 @@ void amount_t::reduce_commodity(const bool keep_price,
annotated_commodity_t&
ann_comm(static_cast<annotated_commodity_t&>(commodity()));
annotated_commodity_t * new_ann_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);
commodity_t * new_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;
}
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)
{
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->date = date;
commodity->tag = tag;
commodity->base = &comm;
assert(commodity->base);
commodity->ptr = comm.ptr;
assert(commodity->ptr);
commodity->qualified_symbol = comm.symbol();

View file

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

View file

@ -46,6 +46,19 @@ balance_t balance_t::price() const
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 {
bool operator()(const amount_t * left, const amount_t * right) const {
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;
if (cost)
*cost /= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity;
if (bal_pair.price && *bal_pair.price && price)
*price /= *bal_pair.price;
return *this;
}
balance_pair_t& balance_pair_t::add(const amount_t& amount,
const amount_t * a_price,
const amount_t * a_cost)
{
if (a_cost && ! cost)
@ -175,13 +184,6 @@ balance_pair_t& balance_pair_t::add(const amount_t& amount,
quantity += amount;
if (cost)
*cost += a_cost ? *a_cost : amount;
if (a_price) {
if (! price)
price = new balance_t(*a_price);
else
*price += *a_price;
}
return *this;
}
@ -290,8 +292,10 @@ void export_balance()
.def("negate", &balance_t::negate)
.def("amount", &balance_t::amount)
.def("value", &balance_t::value)
.def("price", &balance_t::price)
.def("reduce", &balance_t::reduce)
.def("write", &balance_t::write)
.def("valid", &balance_t::valid)
.def("valid", &balance_t::valid)
;
class_< balance_pair_t > ("BalancePair")
@ -368,9 +372,6 @@ void export_balance()
.def("__len__", balance_pair_len)
.def("__getitem__", balance_pair_getitem)
.add_property("price",
make_getter(&balance_pair_t::price,
return_value_policy<reference_existing_object>()))
.add_property("cost",
make_getter(&balance_pair_t::cost,
return_value_policy<reference_existing_object>()))

View file

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

View file

@ -780,9 +780,21 @@ OPT_BEGIN(actual, "L") {
} OPT_END(actual);
OPT_BEGIN(lots, "") {
show_lots = true;
keep_price = keep_date = keep_tag = true;
} 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
@ -1121,6 +1133,9 @@ option_t config_options[CONFIG_OPTIONS_SIZE] = {
{ "init-file", 'i', true, opt_init_file, false },
{ "input-date-format", '\0', true, opt_input_date_format, 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 },
{ "market", 'V', false, opt_market, false },
{ "monthly", 'M', false, opt_monthly, false },

View file

@ -99,7 +99,7 @@ class config_t
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];
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::time_t terminus;
bool keep_price = false;
bool keep_date = false;
bool keep_tag = false;
details_t::details_t(const transaction_t& _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);
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') {

View file

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

View file

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

View file

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

View file

@ -7,8 +7,6 @@
namespace ledger {
bool show_lots = false;
template <>
bool compare_items<transaction_t>::operator()(const transaction_t * left,
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) {
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);
}
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));
}
extern bool show_lots;
//////////////////////////////////////////////////////////////////////
inline void walk_transactions(transactions_list::iterator begin,