diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/amount.cc | 2 | ||||
-rw-r--r-- | src/commodity.cc | 152 | ||||
-rw-r--r-- | src/commodity.h | 85 |
3 files changed, 153 insertions, 86 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> amount_t::value(const optional<datetime_t>& moment) const { if (quantity) { // jww (2008-09-21): 'none' is not the right argument here. - optional<amount_t> amt(commodity().value(none, moment)); + optional<amount_t> 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_t&> -commodity_t::history(const optional<const commodity_t&>& 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; + history_map::iterator i = prices.find(date); + if (i != prices.end()) { + (*i).second = price; + } else { + std::pair<history_map::iterator, bool> result + = prices.insert(history_map::value_type(date, price)); + assert(result.second); } - return none; } -optional<commodity_t::history_t&> -commodity_t::history(const std::vector<const commodity_t *>& commodities) const +bool commodity_t::base_t::history_t::remove_price(const datetime_t& date) { - // 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; + history_map::size_type n = prices.erase(date); + if (n > 0) + return true; + return false; } -void commodity_t::add_price(const datetime_t& date, const amount_t& price) +void commodity_t::base_t::varied_history_t::add_price(const datetime_t& date, + const amount_t& price) { - if (! base->varied_history) - base->varied_history = varied_history_t(); - optional<history_t&> hist = history(price.commodity()); if (! hist) { std::pair<history_by_commodity_map::iterator, bool> result - = base->varied_history->insert(history_by_commodity_map::value_type - (&price.commodity(), history_t())); + = histories.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()) { - (*i).second = price; - } else { - std::pair<history_map::iterator, bool> result - = hist->prices.insert(history_map::value_type(date, price)); - assert(result.second); - } + + hist->add_price(date, price); } -bool commodity_t::remove_price(const datetime_t& date, const commodity_t& comm) +bool commodity_t::base_t::varied_history_t::remove_price(const datetime_t& date, + const commodity_t& comm) { - if (base->varied_history) { - optional<history_t&> 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; - } - } - } + if (optional<history_t&> hist = history(comm)) + return hist->remove_price(date); return false; } optional<amount_t> -commodity_t::value(const history_t& history, - const optional<datetime_t>& moment) +commodity_t::base_t::history_t::find_price(const optional<datetime_t>& moment) { optional<datetime_t> age; optional<amount_t> 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<amount_t> +commodity_t::base_t::varied_history_t::find_price + (const optional<const commodity_t&>& commodity, + const optional<datetime_t>& moment) +{ + return none; +} + +optional<amount_t> +commodity_t::base_t::varied_history_t::find_price + (const std::vector<const commodity_t *>& commodities, + const optional<datetime_t>& moment) +{ + return none; +} + +optional<commodity_t::base_t::history_t&> +commodity_t::base_t::varied_history_t::history + (const optional<const commodity_t&>& 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::history_t&> +commodity_t::base_t::varied_history_t::history + (const std::vector<const commodity_t *>& 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<history_t&> 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<const datetime_t, amount_t> 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<amount_t> find_price(const optional<datetime_t>& moment = none); }; typedef std::map<const commodity_t *, history_t> 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<amount_t> + find_price(const optional<const commodity_t&>& commodity = none, + const optional<datetime_t>& moment = none); + optional<amount_t> + find_price(const std::vector<const commodity_t *>& commodities, + const optional<datetime_t>& moment = none); + + optional<history_t&> + history(const optional<const commodity_t&>& commodity = none); + optional<history_t&> + history(const std::vector<const commodity_t *>& commodities); + }; #define COMMODITY_STYLE_DEFAULTS 0x00 #define COMMODITY_STYLE_SUFFIXED 0x01 @@ -91,10 +115,12 @@ public: optional<amount_t> smaller; optional<amount_t> 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_t&> varied_history() const { +protected: + optional<varied_history_t&> varied_history() { if (base->varied_history) return *base->varied_history; return none; } optional<history_t&> - history(const optional<const commodity_t&>& commodity) const; + history(const optional<const commodity_t&>& commodity); optional<history_t&> - history(const std::vector<const commodity_t *>& commodities) const; + history(const std::vector<const commodity_t *>& commodities); - void add_price(const datetime_t& date, const amount_t& price); - bool remove_price(const datetime_t& date, const commodity_t& comm); + optional<history_t> + find_price(const commodity_t& commodity, + const optional<datetime_t>& moment, + std::vector<bool *>& bools); - optional<amount_t> - value(const history_t& history, - const optional<datetime_t>& moment = none); +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<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); + find_price(const optional<const commodity_t&>& commodity = none, + const optional<datetime_t>& moment = none) { + if (base->varied_history) + return base->varied_history->find_price(commodity, 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); + find_price(const std::vector<const commodity_t *>& commodities, + const optional<datetime_t>& 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<datetime_t>& moment = none, const optional<string>& 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) { |