diff options
-rw-r--r-- | src/amount.cc | 3 | ||||
-rw-r--r-- | src/commodity.cc | 105 | ||||
-rw-r--r-- | src/commodity.h | 33 |
3 files changed, 90 insertions, 51 deletions
diff --git a/src/amount.cc b/src/amount.cc index 8d433ad4..59671f98 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -650,7 +650,8 @@ amount_t& amount_t::in_place_unreduce() optional<amount_t> amount_t::value(const optional<datetime_t>& moment) const { if (quantity) { - optional<amount_t> amt(commodity().value(moment)); + // jww (2008-09-21): 'none' is not the right argument here. + optional<amount_t> amt(commodity().value(none, moment)); if (amt) return (*amt * number()).round(); } else { diff --git a/src/commodity.cc b/src/commodity.cc index 44dab58f..11a53e96 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -43,6 +43,44 @@ namespace ledger { +optional<commodity_t::history_t&> +commodity_t::history(const optional<const commodity_t&>& commodity) const +{ + if (base->varied_history) { + const commodity_t * comm = NULL; + if (! commodity) { + if (base->varied_history->size() > 1) + // jww (2008-09-20): Document which option switch to use here + throw_(commodity_error, "Cannot determine history for '" + << *this << "': prices known for multiple commodities (use -?)"); + comm = (*base->varied_history->begin()).first; + } else { + comm = &(*commodity); + } + + history_by_commodity_map::iterator i = base->varied_history->find(comm); + if (i != base->varied_history->end()) + return (*i).second; + } + return none; +} + +optional<commodity_t::history_t&> +commodity_t::history(const std::vector<const commodity_t *>& commodities) const +{ + // This function differs from the single commodity case avoid in that + // 'commodities' represents a list of preferred valuation commodities. + // If no price can be located in terms of the first commodity, then + // the second is chosen, etc. + + foreach (const commodity_t * commodity, commodities) { + if (optional<commodity_t::history_t&> hist = + history(*commodity)) + return hist; + } + return none; +} + void commodity_t::add_price(const datetime_t& date, const amount_t& price) { if (! base->varied_history) @@ -85,57 +123,42 @@ bool commodity_t::remove_price(const datetime_t& date, const commodity_t& comm) } optional<amount_t> -commodity_t::value(const optional<datetime_t>& moment, - const optional<std::vector<const commodity_t *> >& commodities) +commodity_t::value(const history_t& history, + const optional<datetime_t>& moment) { optional<datetime_t> age; optional<amount_t> price; - optional<history_t&> hist; - - if (base->varied_history) { - const commodity_t * comm = NULL; - if (commodities) { - // Walk the list of commodities, finding the first one applicable - comm = commodities->back(); - } else { - if (base->varied_history->size() > 1) - throw_(commodity_error, - "Cannot find commodity value: multiple possibilities exist"); - comm = (*base->varied_history->begin()).first; - } - hist = history(*comm); - if (hist) { - assert(hist->prices.size() > 0); + if (history.prices.size() == 0) + return none; - if (! moment) { - history_map::reverse_iterator r = hist->prices.rbegin(); - age = (*r).first; - price = (*r).second; - } else { - history_map::iterator i = hist->prices.lower_bound(*moment); - if (i == hist->prices.end()) { - history_map::reverse_iterator r = hist->prices.rbegin(); - age = (*r).first; - price = (*r).second; + if (! moment) { + history_map::const_reverse_iterator r = history.prices.rbegin(); + age = (*r).first; + price = (*r).second; + } else { + history_map::const_iterator i = history.prices.lower_bound(*moment); + if (i == history.prices.end()) { + history_map::const_reverse_iterator r = history.prices.rbegin(); + age = (*r).first; + price = (*r).second; + } else { + age = (*i).first; + if (*moment != *age) { + if (i != history.prices.begin()) { + --i; + age = (*i).first; + price = (*i).second; } else { - age = (*i).first; - if (*moment != *age) { - if (i != hist->prices.begin()) { - --i; - age = (*i).first; - price = (*i).second; - } else { - age = none; - } - } else { - price = (*i).second; - } + age = none; } + } else { + price = (*i).second; } } } +#if 0 if (! has_flags(COMMODITY_STYLE_NOMARKET) && parent().get_quote) { if (optional<amount_t> quote = parent().get_quote (*this, age, moment, @@ -143,6 +166,8 @@ commodity_t::value(const optional<datetime_t>& moment, (*hist->prices.rbegin()).first : optional<datetime_t>()))) return *quote; } +#endif + return price; } diff --git a/src/commodity.h b/src/commodity.h index 06e64a7f..6b1001cd 100644 --- a/src/commodity.h +++ b/src/commodity.h @@ -201,21 +201,34 @@ public: return *base->varied_history; return none; } - optional<history_t&> history(const commodity_t& comm) const { - if (base->varied_history) { - history_by_commodity_map::iterator i = base->varied_history->find(&comm); - if (i != base->varied_history->end()) - return (*i).second; - } - return none; - } + + optional<history_t&> + history(const optional<const commodity_t&>& commodity) const; + optional<history_t&> + history(const std::vector<const commodity_t *>& commodities) const; void add_price(const datetime_t& date, const amount_t& price); bool remove_price(const datetime_t& date, const commodity_t& comm); optional<amount_t> - value(const optional<datetime_t>& moment = none, - const optional<std::vector<const commodity_t *> >& commodities = none); + value(const history_t& history, + const optional<datetime_t>& moment = none); + + optional<amount_t> + value(const optional<const commodity_t&>& commodity = none, + const optional<datetime_t>& moment = none) { + if (optional<history_t&> hist = history(commodity)) + return value(*hist, moment); + return none; + } + + optional<amount_t> + value(const std::vector<const commodity_t *>& commodities, + const optional<datetime_t>& moment = none) { + if (optional<history_t&> hist = history(commodities)) + return value(*hist, moment); + return none; + } static void exchange(commodity_t& commodity, const amount_t& per_unit_cost, |