From 697f6a6bce46e75fcb37c38da9f16ca2f1a8e9a3 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sat, 20 Sep 2008 14:46:18 -0400 Subject: Began initial work to support specifying a series of commodities to -V. --- src/cache.cc | 2 +- src/commodity.cc | 102 +++++++++++++++++++++++++++++++++++-------------------- src/commodity.h | 60 +++++++++++++++++++++----------- 3 files changed, 107 insertions(+), 57 deletions(-) (limited to 'src') 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 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()) { (*i).second = price; } else { std::pair 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 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 commodity_t::value(const optional& moment) +optional +commodity_t::value(const optional& moment, + const optional >& commodities) { optional age; - optional price; + optional price; + optional 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 commodity_t::value(const optional& moment) if (! has_flags(COMMODITY_STYLE_NOMARKET) && parent().get_quote) { if (optional quote = parent().get_quote (*this, age, moment, - (base->history && base->history->prices.size() > 0 ? - (*base->history->prices.rbegin()).first : optional()))) + (hist && hist->prices.size() > 0 ? + (*hist->prices.rbegin()).first : optional()))) 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 @@ -62,14 +64,17 @@ public: base_t(); public: - typedef std::map history_map; - typedef std::pair history_pair; + typedef std::map history_map; struct history_t { history_map prices; ptime last_lookup; }; + typedef std::map 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 name; - optional note; - optional history; - optional smaller; - optional larger; + string symbol; + amount_t::precision_t precision; + optional name; + optional note; + optional varied_history; + optional smaller; + optional 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; @@ -188,14 +196,30 @@ public: base->larger = arg; } - optional history() const { - return base->history; + optional varied_history() const { + if (base->varied_history) + return *base->varied_history; + return none; + } + optional 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 value(const optional& moment = none); + optional + value(const optional& moment = none, + const optional >& 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, -- cgit v1.2.3