A further simplification of -V and -X

With -X COMM, all values are computed in terms of COMM, regardless.

With -V, only secondary commodities will ever be computed, never
primaries.  Further, if a secondary commodities has an associated price,
the valuation is done in terms of that price's commodity.
This commit is contained in:
John Wiegley 2010-06-07 09:49:17 -04:00
parent ae8ab81062
commit be6cef93c4
14 changed files with 64 additions and 68 deletions

View file

@ -724,8 +724,7 @@ void amount_t::in_place_unreduce()
} }
optional<amount_t> optional<amount_t>
amount_t::value(const bool primary_only, amount_t::value(const optional<datetime_t>& moment,
const optional<datetime_t>& moment,
const optional<commodity_t&>& in_terms_of) const const optional<commodity_t&>& in_terms_of) const
{ {
if (quantity) { if (quantity) {
@ -740,28 +739,33 @@ amount_t::value(const bool primary_only,
"amount_t::value: in_terms_of = " << in_terms_of->symbol()); "amount_t::value: in_terms_of = " << in_terms_of->symbol());
#endif #endif
if (has_commodity() && if (has_commodity() &&
(! primary_only || ! commodity().has_flags(COMMODITY_PRIMARY))) { (in_terms_of || ! commodity().has_flags(COMMODITY_PRIMARY))) {
if (in_terms_of && optional<price_point_t> point;
commodity().referent() == in_terms_of->referent()) { optional<commodity_t&> comm(in_terms_of);
if (comm && commodity().referent() == comm->referent()) {
return *this; return *this;
} }
else if (has_annotation() && annotation().price && else if (has_annotation() && annotation().price) {
annotation().has_flags(ANNOTATION_PRICE_FIXATED)) { if (annotation().has_flags(ANNOTATION_PRICE_FIXATED)) {
amount_t price(*annotation().price); point = price_point_t();
price.multiply(*this, true); point->price = *annotation().price;
price.in_place_round(); }
return price; else if (! in_terms_of) {
comm = annotation().price->commodity();
}
}
if (! point) {
point = commodity().find_price(comm, moment);
// Whether a price was found or not, check whether we should attempt
// to download a price from the Internet. This is done if (a) no
// price was found, or (b) the price is "stale" according to the
// setting of --price-exp.
if (point)
point = commodity().check_for_updated_price(point, moment, comm);
} }
else {
optional<price_point_t> point =
commodity().find_price(in_terms_of, moment);
// Whether a price was found or not, check whether we should
// attempt to download a price from the Internet. This is done
// if (a) no price was found, or (b) the price is "stale"
// according to the setting of --price-exp.
point = commodity().check_for_updated_price(point, moment,
in_terms_of);
if (point) { if (point) {
amount_t price(point->price); amount_t price(point->price);
price.multiply(*this, true); price.multiply(*this, true);
@ -769,7 +773,6 @@ amount_t::value(const bool primary_only,
return price; return price;
} }
} }
}
} else { } else {
throw_(amount_error, throw_(amount_error,
_("Cannot determine value of an uninitialized amount")); _("Cannot determine value of an uninitialized amount"));

View file

@ -399,8 +399,7 @@ public:
$100.00. $100.00.
*/ */
optional<amount_t> optional<amount_t>
value(const bool primary_only = true, value(const optional<datetime_t>& moment = none,
const optional<datetime_t>& moment = none,
const optional<commodity_t&>& in_terms_of = none) const; const optional<commodity_t&>& in_terms_of = none) const;
amount_t price() const; amount_t price() const;

View file

@ -185,16 +185,14 @@ balance_t& balance_t::operator/=(const amount_t& amt)
} }
optional<balance_t> optional<balance_t>
balance_t::value(const bool primary_only, balance_t::value(const optional<datetime_t>& moment,
const optional<datetime_t>& moment,
const optional<commodity_t&>& in_terms_of) const const optional<commodity_t&>& in_terms_of) const
{ {
balance_t temp; balance_t temp;
bool resolved = false; bool resolved = false;
foreach (const amounts_map::value_type& pair, amounts) { foreach (const amounts_map::value_type& pair, amounts) {
if (optional<amount_t> val = pair.second.value(primary_only, moment, if (optional<amount_t> val = pair.second.value(moment, in_terms_of)) {
in_terms_of)) {
temp += *val; temp += *val;
resolved = true; resolved = true;
} else { } else {

View file

@ -384,8 +384,7 @@ public:
} }
optional<balance_t> optional<balance_t>
value(const bool primary_only = false, value(const optional<datetime_t>& moment = none,
const optional<datetime_t>& moment = none,
const optional<commodity_t&>& in_terms_of = none) const; const optional<commodity_t&>& in_terms_of = none) const;
balance_t price() const; balance_t price() const;

View file

@ -264,10 +264,6 @@ commodity_t::varied_history_t::find_price(const commodity_t& source,
if (comm == source) if (comm == source)
continue; continue;
// Only value secondary commodities in terms of primary ones
if (! commodity && ! comm.has_flags(COMMODITY_PRIMARY))
continue;
DEBUG_INDENT("commodity.prices.find", indent + 1); DEBUG_INDENT("commodity.prices.find", indent + 1);
DEBUG("commodity.prices.find", DEBUG("commodity.prices.find",
"searching for price via commodity '" << comm << "'"); "searching for price via commodity '" << comm << "'");
@ -370,8 +366,7 @@ commodity_t::find_price(const optional<commodity_t&>& commodity,
#endif #endif
) const ) const
{ {
if (! has_flags(COMMODITY_WALKED) && base->varied_history && if (! has_flags(COMMODITY_WALKED) && base->varied_history) {
(commodity || ! has_flags(COMMODITY_PRIMARY))) {
optional<base_t::time_and_commodity_t> pair; optional<base_t::time_and_commodity_t> pair;
#if defined(VERIFY_ON) #if defined(VERIFY_ON)
optional<price_point_t> checkpoint; optional<price_point_t> checkpoint;

View file

@ -59,6 +59,10 @@ struct price_point_t
datetime_t when; datetime_t when;
amount_t price; amount_t price;
price_point_t() {}
price_point_t(datetime_t _when, amount_t _price)
: when(_when), price(_price) {}
bool operator==(const price_point_t& other) const { bool operator==(const price_point_t& other) const {
return when == other.when && price == other.price; return when == other.when && price == other.price;
} }

View file

@ -45,16 +45,16 @@ using namespace boost::python;
namespace { namespace {
boost::optional<amount_t> py_value_0(const amount_t& amount) { boost::optional<amount_t> py_value_0(const amount_t& amount) {
return amount.value(false, CURRENT_TIME()); return amount.value(CURRENT_TIME());
} }
boost::optional<amount_t> py_value_1(const amount_t& amount, boost::optional<amount_t> py_value_1(const amount_t& amount,
commodity_t& in_terms_of) { commodity_t& in_terms_of) {
return amount.value(false, CURRENT_TIME(), in_terms_of); return amount.value(CURRENT_TIME(), in_terms_of);
} }
boost::optional<amount_t> py_value_2(const amount_t& amount, boost::optional<amount_t> py_value_2(const amount_t& amount,
commodity_t& in_terms_of, commodity_t& in_terms_of,
datetime_t& moment) { datetime_t& moment) {
return amount.value(false, moment, in_terms_of); return amount.value(moment, in_terms_of);
} }
void py_parse_2(amount_t& amount, object in, unsigned char flags) { void py_parse_2(amount_t& amount, object in, unsigned char flags) {

View file

@ -45,16 +45,16 @@ using namespace boost::python;
namespace { namespace {
boost::optional<balance_t> py_value_0(const balance_t& balance) { boost::optional<balance_t> py_value_0(const balance_t& balance) {
return balance.value(false, CURRENT_TIME()); return balance.value(CURRENT_TIME());
} }
boost::optional<balance_t> py_value_1(const balance_t& balance, boost::optional<balance_t> py_value_1(const balance_t& balance,
commodity_t& in_terms_of) { commodity_t& in_terms_of) {
return balance.value(false, CURRENT_TIME(), in_terms_of); return balance.value(CURRENT_TIME(), in_terms_of);
} }
boost::optional<balance_t> py_value_2(const balance_t& balance, boost::optional<balance_t> py_value_2(const balance_t& balance,
commodity_t& in_terms_of, commodity_t& in_terms_of,
datetime_t& moment) { datetime_t& moment) {
return balance.value(false, moment, in_terms_of); return balance.value(moment, in_terms_of);
} }
boost::optional<amount_t> boost::optional<amount_t>

View file

@ -48,16 +48,16 @@ BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(set_string_overloads, set_string, 0, 2)
namespace { namespace {
boost::optional<value_t> py_value_0(const value_t& value) { boost::optional<value_t> py_value_0(const value_t& value) {
return value.value(false, CURRENT_TIME()); return value.value(CURRENT_TIME());
} }
boost::optional<value_t> py_value_1(const value_t& value, boost::optional<value_t> py_value_1(const value_t& value,
commodity_t& in_terms_of) { commodity_t& in_terms_of) {
return value.value(false, CURRENT_TIME(), in_terms_of); return value.value(CURRENT_TIME(), in_terms_of);
} }
boost::optional<value_t> py_value_2(const value_t& value, boost::optional<value_t> py_value_2(const value_t& value,
commodity_t& in_terms_of, commodity_t& in_terms_of,
datetime_t& moment) { datetime_t& moment) {
return value.value(false, moment, in_terms_of); return value.value(moment, in_terms_of);
} }
PyObject * py_base_type(value_t& value) PyObject * py_base_type(value_t& value)

View file

@ -466,7 +466,7 @@ value_t report_t::fn_market(call_scope_t& scope)
/* add_prices= */ false, /* add_prices= */ false,
moment); moment);
else else
result = args.value_at(0).value(true, moment); result = args.value_at(0).value(moment);
if (! result.is_null()) if (! result.is_null())
return result; return result;

View file

@ -1401,8 +1401,7 @@ bool value_t::is_zero() const
return false; return false;
} }
value_t value_t::value(const bool primary_only, value_t value_t::value(const optional<datetime_t>& moment,
const optional<datetime_t>& moment,
const optional<commodity_t&>& in_terms_of) const const optional<commodity_t&>& in_terms_of) const
{ {
switch (type()) { switch (type()) {
@ -1411,13 +1410,13 @@ value_t value_t::value(const bool primary_only,
case AMOUNT: case AMOUNT:
if (optional<amount_t> val = if (optional<amount_t> val =
as_amount().value(primary_only, moment, in_terms_of)) as_amount().value(moment, in_terms_of))
return *val; return *val;
return NULL_VALUE; return NULL_VALUE;
case BALANCE: case BALANCE:
if (optional<balance_t> bal = if (optional<balance_t> bal =
as_balance().value(primary_only, moment, in_terms_of)) as_balance().value(moment, in_terms_of))
return *bal; return *bal;
return NULL_VALUE; return NULL_VALUE;
@ -1455,7 +1454,7 @@ value_t value_t::exchange_commodities(const std::string& commodities,
if (commodity_t * commodity = if (commodity_t * commodity =
commodity_pool_t::current_pool->parse_price_expression(p, add_prices, commodity_pool_t::current_pool->parse_price_expression(p, add_prices,
moment)) { moment)) {
value_t result = value(false, moment, *commodity); value_t result = value(moment, *commodity);
if (! result.is_null()) if (! result.is_null())
return result; return result;
} }

View file

@ -476,8 +476,7 @@ public:
void in_place_unreduce(); // exists for efficiency's sake void in_place_unreduce(); // exists for efficiency's sake
// Return the "market value" of a given value at a specific time. // Return the "market value" of a given value at a specific time.
value_t value(const bool primary_only = false, value_t value(const optional<datetime_t>& moment = none,
const optional<datetime_t>& moment = none,
const optional<commodity_t&>& in_terms_of = none) const; const optional<commodity_t&>& in_terms_of = none) const;
value_t price() const; value_t price() const;

View file

@ -4,16 +4,16 @@
>>>2 >>>2
While parsing file "$sourcepath/src/amount.h", line 66: While parsing file "$sourcepath/src/amount.h", line 66:
Error: No quantity specified for amount Error: No quantity specified for amount
While parsing file "$sourcepath/src/amount.h", line 726: While parsing file "$sourcepath/src/amount.h", line 725:
Error: Invalid date/time: line amount_t amoun Error: Invalid date/time: line amount_t amoun
While parsing file "$sourcepath/src/amount.h", line 732: While parsing file "$sourcepath/src/amount.h", line 731:
Error: Invalid date/time: line string amount_ Error: Invalid date/time: line string amount_
While parsing file "$sourcepath/src/amount.h", line 738: While parsing file "$sourcepath/src/amount.h", line 737:
Error: Invalid date/time: line string amount_ Error: Invalid date/time: line string amount_
While parsing file "$sourcepath/src/amount.h", line 744: While parsing file "$sourcepath/src/amount.h", line 743:
Error: Invalid date/time: line string amount_ Error: Invalid date/time: line string amount_
While parsing file "$sourcepath/src/amount.h", line 750: While parsing file "$sourcepath/src/amount.h", line 749:
Error: Invalid date/time: line std::ostream& Error: Invalid date/time: line std::ostream&
While parsing file "$sourcepath/src/amount.h", line 757: While parsing file "$sourcepath/src/amount.h", line 756:
Error: Invalid date/time: line std::istream& Error: Invalid date/time: line std::istream&
=== 7 === 7

View file

@ -73,11 +73,11 @@ void CommodityTestCase::testPriceHistory()
cad.add_price(jan17_06, amount_t("$1.11")); cad.add_price(jan17_06, amount_t("$1.11"));
#ifndef NOT_FOR_PYTHON #ifndef NOT_FOR_PYTHON
optional<amount_t> amt = x1.value(false, feb28_07sbm); optional<amount_t> amt = x1.value(feb28_07sbm);
assertTrue(amt); assertTrue(amt);
assertEqual(amount_t("$1831.83"), *amt); assertEqual(amount_t("$1831.83"), *amt);
amt = x1.value(false, CURRENT_TIME()); amt = x1.value(CURRENT_TIME());
assertTrue(amt); assertTrue(amt);
assertEqual(string("$2124.12"), amt->to_string()); assertEqual(string("$2124.12"), amt->to_string());
#ifdef INTEGER_MATH #ifdef INTEGER_MATH
@ -86,18 +86,18 @@ void CommodityTestCase::testPriceHistory()
assertEqual(string("$2124.122"), amt->to_fullstring()); assertEqual(string("$2124.122"), amt->to_fullstring());
#endif #endif
amt = x1.value(false, CURRENT_TIME(), euro); amt = x1.value(CURRENT_TIME(), euro);
assertTrue(amt); assertTrue(amt);
assertEqual(string("EUR 1366.87"), amt->rounded().to_string()); assertEqual(string("EUR 1366.87"), amt->rounded().to_string());
// Add a newer Euro pricing // Add a newer Euro pricing
aapl.add_price(jan17_07, amount_t("EUR 23.00")); aapl.add_price(jan17_07, amount_t("EUR 23.00"));
amt = x1.value(false, CURRENT_TIME(), euro); amt = x1.value(CURRENT_TIME(), euro);
assertTrue(amt); assertTrue(amt);
assertEqual(string("EUR 2302.30"), amt->to_string()); assertEqual(string("EUR 2302.30"), amt->to_string());
amt = x1.value(false, CURRENT_TIME(), cad); amt = x1.value(CURRENT_TIME(), cad);
assertTrue(amt); assertTrue(amt);
assertEqual(string("CAD 3223.22"), amt->to_string()); assertEqual(string("CAD 3223.22"), amt->to_string());
#endif // NOT_FOR_PYTHON #endif // NOT_FOR_PYTHON