From 6007e3cbfe1e2b5a94e71eccc30f7298f0983535 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sun, 21 Sep 2008 10:26:38 -0400 Subject: [PATCH] Did more restructing of commodity price histories, although the completed find_price does not work yet. --- src/amount.cc | 2 +- src/commodity.cc | 168 ++++++++++++++++++++++++++--------------------- src/commodity.h | 87 ++++++++++++++++++------ 3 files changed, 162 insertions(+), 95 deletions(-) diff --git a/src/amount.cc b/src/amount.cc index 59671f98..c052cd23 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -651,7 +651,7 @@ optional amount_t::value(const optional& moment) const { if (quantity) { // jww (2008-09-21): 'none' is not the right argument here. - optional amt(commodity().value(none, moment)); + optional amt(commodity().find_price(none, moment)); if (amt) return (*amt * number()).round(); } else { diff --git a/src/commodity.cc b/src/commodity.cc index 11a53e96..f8ab523e 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -43,109 +43,75 @@ namespace ledger { -optional -commodity_t::history(const optional& commodity) const +void commodity_t::base_t::history_t::add_price(const datetime_t& date, + const amount_t& price) { - 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(const std::vector& 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 hist = - history(*commodity)) - return hist; - } - return none; -} - -void commodity_t::add_price(const datetime_t& date, const amount_t& price) -{ - if (! base->varied_history) - base->varied_history = varied_history_t(); - - optional hist = history(price.commodity()); - if (! hist) { - std::pair result - = base->varied_history->insert(history_by_commodity_map::value_type - (&price.commodity(), history_t())); - assert(result.second); - hist = (*result.first).second; - } - assert(hist); - - history_map::iterator i = hist->prices.find(date); - if (i != hist->prices.end()) { + history_map::iterator i = prices.find(date); + if (i != prices.end()) { (*i).second = price; } else { std::pair result - = hist->prices.insert(history_map::value_type(date, price)); + = prices.insert(history_map::value_type(date, price)); assert(result.second); } } -bool commodity_t::remove_price(const datetime_t& date, const commodity_t& comm) +bool commodity_t::base_t::history_t::remove_price(const datetime_t& date) { - if (base->varied_history) { - optional hist = history(comm); - if (hist) { - history_map::size_type n = hist->prices.erase(date); - if (n > 0) { - if (hist->prices.empty()) - hist.reset(); - return true; - } - } + history_map::size_type n = prices.erase(date); + if (n > 0) + return true; + return false; +} + +void commodity_t::base_t::varied_history_t::add_price(const datetime_t& date, + const amount_t& price) +{ + optional hist = history(price.commodity()); + if (! hist) { + std::pair result + = histories.insert(history_by_commodity_map::value_type + (&price.commodity(), history_t())); + assert(result.second); + + hist = (*result.first).second; } + assert(hist); + + hist->add_price(date, price); +} + +bool commodity_t::base_t::varied_history_t::remove_price(const datetime_t& date, + const commodity_t& comm) +{ + if (optional hist = history(comm)) + return hist->remove_price(date); return false; } optional -commodity_t::value(const history_t& history, - const optional& moment) +commodity_t::base_t::history_t::find_price(const optional& moment) { optional age; optional price; - if (history.prices.size() == 0) + if (prices.size() == 0) return none; if (! moment) { - history_map::const_reverse_iterator r = history.prices.rbegin(); + history_map::const_reverse_iterator r = 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(); + history_map::const_iterator i = prices.lower_bound(*moment); + if (i == prices.end()) { + history_map::const_reverse_iterator r = prices.rbegin(); age = (*r).first; price = (*r).second; } else { age = (*i).first; if (*moment != *age) { - if (i != history.prices.begin()) { + if (i != prices.begin()) { --i; age = (*i).first; price = (*i).second; @@ -171,6 +137,60 @@ commodity_t::value(const history_t& history, return price; } +optional +commodity_t::base_t::varied_history_t::find_price + (const optional& commodity, + const optional& moment) +{ + return none; +} + +optional +commodity_t::base_t::varied_history_t::find_price + (const std::vector& commodities, + const optional& moment) +{ + return none; +} + +optional +commodity_t::base_t::varied_history_t::history + (const optional& commodity) +{ + const commodity_t * comm = NULL; + if (! commodity) { + if (histories.size() > 1) + // jww (2008-09-20): Document which option switch to use here + throw_(commodity_error, + "Cannot determine price history: prices known for multiple commodities (use -?)"); + comm = (*histories.begin()).first; + } else { + comm = &(*commodity); + } + + history_by_commodity_map::iterator i = histories.find(comm); + if (i != histories.end()) + return (*i).second; + + return none; +} + +optional +commodity_t::base_t::varied_history_t::history + (const std::vector& commodities) +{ + // 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 hist = history(*commodity)) + return hist; + } + return none; +} + void commodity_t::exchange(commodity_t& commodity, const amount_t& per_unit_cost, const datetime_t& moment) diff --git a/src/commodity.h b/src/commodity.h index 6b1001cd..29011a7f 100644 --- a/src/commodity.h +++ b/src/commodity.h @@ -66,14 +66,38 @@ public: public: typedef std::map history_map; - struct history_t { + struct history_t + { history_map prices; ptime last_lookup; + + void add_price(const datetime_t& date, const amount_t& price); + bool remove_price(const datetime_t& date); + + optional find_price(const optional& moment = none); }; typedef std::map history_by_commodity_map; - typedef history_by_commodity_map varied_history_t; + struct varied_history_t + { + history_by_commodity_map histories; + + void add_price(const datetime_t& date, const amount_t& price); + bool remove_price(const datetime_t& date, const commodity_t& commodity); + + optional + find_price(const optional& commodity = none, + const optional& moment = none); + optional + find_price(const std::vector& commodities, + const optional& moment = none); + + optional + history(const optional& commodity = none); + optional + history(const std::vector& commodities); + }; #define COMMODITY_STYLE_DEFAULTS 0x00 #define COMMODITY_STYLE_SUFFIXED 0x01 @@ -91,10 +115,12 @@ public: optional smaller; optional larger; + mutable bool searched; + public: explicit base_t(const string& _symbol) : supports_flags<>(COMMODITY_STYLE_DEFAULTS), - symbol(_symbol), precision(0) { + symbol(_symbol), precision(0), searched(false) { TRACE_CTOR(base_t, "const string&"); } ~base_t() { @@ -196,40 +222,58 @@ public: base->larger = arg; } - optional varied_history() const { +protected: + optional varied_history() { if (base->varied_history) return *base->varied_history; return none; } optional - history(const optional& commodity) const; + history(const optional& commodity); optional - history(const std::vector& commodities) const; + history(const std::vector& commodities); - void add_price(const datetime_t& date, const amount_t& price); - bool remove_price(const datetime_t& date, const commodity_t& comm); + optional + find_price(const commodity_t& commodity, + const optional& moment, + std::vector& bools); + +public: + // These methods provide a transparent pass-through to the underlying + // base->varied_history object. + + void add_price(const datetime_t& date, const amount_t& price) { + if (! base->varied_history) + base->varied_history = varied_history_t(); + + base->varied_history->add_price(date, price); + } + bool remove_price(const datetime_t& date, const commodity_t& commodity) { + if (base->varied_history) + base->varied_history->remove_price(date, commodity); + return false; + } optional - value(const history_t& history, - const optional& moment = none); - - optional - value(const optional& commodity = none, - const optional& moment = none) { - if (optional hist = history(commodity)) - return value(*hist, moment); + find_price(const optional& commodity = none, + const optional& moment = none) { + if (base->varied_history) + return base->varied_history->find_price(commodity, moment); return none; } optional - value(const std::vector& commodities, - const optional& moment = none) { - if (optional hist = history(commodities)) - return value(*hist, moment); + find_price(const std::vector& commodities, + const optional& moment = none) { + if (base->varied_history) + return base->varied_history->find_price(commodities, moment); return none; } + // Methods to exchange one commodity for another, while recording the + // factored price. + static void exchange(commodity_t& commodity, const amount_t& per_unit_cost, const datetime_t& moment); @@ -246,6 +290,9 @@ public: const optional& moment = none, const optional& tag = none); + // Methods related to parsing, reading, writing, etc., the commodity + // itself. + static void parse_symbol(std::istream& in, string& symbol); static void parse_symbol(char *& p, string& symbol); static string parse_symbol(std::istream& in) {