diff options
-rw-r--r-- | src/cache.cc | 2 | ||||
-rw-r--r-- | src/commodity.cc | 102 | ||||
-rw-r--r-- | src/commodity.h | 60 |
3 files changed, 107 insertions, 57 deletions
diff --git a/src/cache.cc b/src/cache.cc index 0501cee6..64b7c751 100644 --- a/src/cache.cc +++ b/src/cache.cc @@ -290,7 +290,7 @@ void read_commodity_base_extra(const char *& data, // duplicated (and thus not lost when the journal's item_pool is deleted). if (! commodity->history) commodity->history = commodity_t::history_t(); - commodity->history->prices.insert(commodity_t::base_t::history_pair(when, amt)); + commodity->history->prices.insert(commodity_t::history_t::value_type(when, amt)); read_history = true; } diff --git a/src/commodity.cc b/src/commodity.cc index 29bb2f56..44dab58f 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -45,62 +45,92 @@ namespace ledger { void commodity_t::add_price(const datetime_t& date, const amount_t& price) { - if (! base->history) - base->history = history_t(); - - history_map::iterator i = base->history->prices.find(date); - if (i != base->history->prices.end()) { + 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())); + 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 - = base->history->prices.insert(history_map::value_type(date, price)); + = hist->prices.insert(history_map::value_type(date, price)); assert(result.second); } } -bool commodity_t::remove_price(const datetime_t& date) +bool commodity_t::remove_price(const datetime_t& date, const commodity_t& comm) { - if (base->history) { - history_map::size_type n = base->history->prices.erase(date); - if (n > 0) { - if (base->history->prices.empty()) - base->history.reset(); - return true; + 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; + } } } return false; } -optional<amount_t> commodity_t::value(const optional<datetime_t>& moment) +optional<amount_t> +commodity_t::value(const optional<datetime_t>& moment, + const optional<std::vector<const commodity_t *> >& commodities) { optional<datetime_t> age; - optional<amount_t> price; + 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; + } - if (base->history) { - assert(base->history->prices.size() > 0); + hist = history(*comm); + if (hist) { + assert(hist->prices.size() > 0); - if (! moment) { - history_map::reverse_iterator r = base->history->prices.rbegin(); - age = (*r).first; - price = (*r).second; - } else { - history_map::iterator i = base->history->prices.lower_bound(*moment); - if (i == base->history->prices.end()) { - history_map::reverse_iterator r = base->history->prices.rbegin(); + if (! moment) { + history_map::reverse_iterator r = hist->prices.rbegin(); age = (*r).first; price = (*r).second; } else { - age = (*i).first; - if (*moment != *age) { - if (i != base->history->prices.begin()) { - --i; - age = (*i).first; - price = (*i).second; + 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; + } else { + age = (*i).first; + if (*moment != *age) { + if (i != hist->prices.begin()) { + --i; + age = (*i).first; + price = (*i).second; + } else { + age = none; + } } else { - age = none; + price = (*i).second; } - } else { - price = (*i).second; } } } @@ -109,8 +139,8 @@ optional<amount_t> commodity_t::value(const optional<datetime_t>& moment) if (! has_flags(COMMODITY_STYLE_NOMARKET) && parent().get_quote) { if (optional<amount_t> quote = parent().get_quote (*this, age, moment, - (base->history && base->history->prices.size() > 0 ? - (*base->history->prices.rbegin()).first : optional<datetime_t>()))) + (hist && hist->prices.size() > 0 ? + (*hist->prices.rbegin()).first : optional<datetime_t>()))) return *quote; } return price; diff --git a/src/commodity.h b/src/commodity.h index af90f6b8..06e64a7f 100644 --- a/src/commodity.h +++ b/src/commodity.h @@ -50,6 +50,8 @@ namespace ledger { +DECLARE_EXCEPTION(commodity_error, std::runtime_error); + class commodity_t : public delegates_flags<>, public equality_comparable1<commodity_t, noncopyable> @@ -62,14 +64,17 @@ public: base_t(); public: - typedef std::map<const datetime_t, amount_t> history_map; - typedef std::pair<const datetime_t, amount_t> history_pair; + typedef std::map<const datetime_t, amount_t> history_map; struct history_t { history_map prices; ptime last_lookup; }; + typedef std::map<const commodity_t *, history_t> history_by_commodity_map; + + typedef history_by_commodity_map varied_history_t; + #define COMMODITY_STYLE_DEFAULTS 0x00 #define COMMODITY_STYLE_SUFFIXED 0x01 #define COMMODITY_STYLE_SEPARATED 0x02 @@ -78,13 +83,13 @@ public: #define COMMODITY_STYLE_NOMARKET 0x10 #define COMMODITY_STYLE_BUILTIN 0x20 - string symbol; - amount_t::precision_t precision; - optional<string> name; - optional<string> note; - optional<history_t> history; - optional<amount_t> smaller; - optional<amount_t> larger; + string symbol; + amount_t::precision_t precision; + optional<string> name; + optional<string> note; + optional<varied_history_t> varied_history; + optional<amount_t> smaller; + optional<amount_t> larger; public: explicit base_t(const string& _symbol) @@ -100,9 +105,12 @@ public: public: static bool symbol_needs_quotes(const string& symbol); - typedef base_t::history_t history_t; - typedef base_t::history_map history_map; - typedef uint_least32_t ident_t; + typedef base_t::history_t history_t; + typedef base_t::history_map history_map; + typedef base_t::varied_history_t varied_history_t; + typedef uint_least32_t ident_t; + + typedef base_t::history_by_commodity_map history_by_commodity_map; shared_ptr<base_t> base; @@ -188,14 +196,30 @@ public: base->larger = arg; } - optional<history_t> history() const { - return base->history; + optional<varied_history_t&> varied_history() const { + if (base->varied_history) + 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; } void add_price(const datetime_t& date, const amount_t& price); - bool remove_price(const datetime_t& date); + bool remove_price(const datetime_t& date, const commodity_t& comm); - optional<amount_t> value(const optional<datetime_t>& moment = none); + optional<amount_t> + value(const optional<datetime_t>& moment = none, + const optional<std::vector<const commodity_t *> >& commodities = none); + + static void exchange(commodity_t& commodity, + const amount_t& per_unit_cost, + const datetime_t& moment); struct cost_breakdown_t { amount_t amount; @@ -203,10 +227,6 @@ public: amount_t basis_cost; }; - static void exchange(commodity_t& commodity, - const amount_t& per_unit_cost, - const datetime_t& moment); - static cost_breakdown_t exchange(const amount_t& amount, const amount_t& cost, const bool is_per_unit = false, |