Began initial work to support specifying a series of commodities to -V.

This commit is contained in:
John Wiegley 2008-09-20 14:46:18 -04:00
parent e914b476e9
commit 697f6a6bce
3 changed files with 107 additions and 57 deletions

View file

@ -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). // duplicated (and thus not lost when the journal's item_pool is deleted).
if (! commodity->history) if (! commodity->history)
commodity->history = commodity_t::history_t(); 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; read_history = true;
} }

View file

@ -45,54 +45,83 @@ namespace ledger {
void commodity_t::add_price(const datetime_t& date, const amount_t& price) void commodity_t::add_price(const datetime_t& date, const amount_t& price)
{ {
if (! base->history) if (! base->varied_history)
base->history = history_t(); base->varied_history = varied_history_t();
history_map::iterator i = base->history->prices.find(date); optional<history_t&> hist = history(price.commodity());
if (i != base->history->prices.end()) { 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; (*i).second = price;
} else { } else {
std::pair<history_map::iterator, bool> result 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); 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) { if (base->varied_history) {
history_map::size_type n = base->history->prices.erase(date); optional<history_t&> hist = history(comm);
if (hist) {
history_map::size_type n = hist->prices.erase(date);
if (n > 0) { if (n > 0) {
if (base->history->prices.empty()) if (hist->prices.empty())
base->history.reset(); hist.reset();
return true; return true;
} }
} }
}
return false; 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<datetime_t> age;
optional<amount_t> price; optional<amount_t> price;
optional<history_t&> hist;
if (base->history) { if (base->varied_history) {
assert(base->history->prices.size() > 0); 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 (! moment) { if (! moment) {
history_map::reverse_iterator r = base->history->prices.rbegin(); history_map::reverse_iterator r = hist->prices.rbegin();
age = (*r).first; age = (*r).first;
price = (*r).second; price = (*r).second;
} else { } else {
history_map::iterator i = base->history->prices.lower_bound(*moment); history_map::iterator i = hist->prices.lower_bound(*moment);
if (i == base->history->prices.end()) { if (i == hist->prices.end()) {
history_map::reverse_iterator r = base->history->prices.rbegin(); history_map::reverse_iterator r = hist->prices.rbegin();
age = (*r).first; age = (*r).first;
price = (*r).second; price = (*r).second;
} else { } else {
age = (*i).first; age = (*i).first;
if (*moment != *age) { if (*moment != *age) {
if (i != base->history->prices.begin()) { if (i != hist->prices.begin()) {
--i; --i;
age = (*i).first; age = (*i).first;
price = (*i).second; price = (*i).second;
@ -105,12 +134,13 @@ optional<amount_t> commodity_t::value(const optional<datetime_t>& moment)
} }
} }
} }
}
if (! has_flags(COMMODITY_STYLE_NOMARKET) && parent().get_quote) { if (! has_flags(COMMODITY_STYLE_NOMARKET) && parent().get_quote) {
if (optional<amount_t> quote = parent().get_quote if (optional<amount_t> quote = parent().get_quote
(*this, age, moment, (*this, age, moment,
(base->history && base->history->prices.size() > 0 ? (hist && hist->prices.size() > 0 ?
(*base->history->prices.rbegin()).first : optional<datetime_t>()))) (*hist->prices.rbegin()).first : optional<datetime_t>())))
return *quote; return *quote;
} }
return price; return price;

View file

@ -50,6 +50,8 @@
namespace ledger { namespace ledger {
DECLARE_EXCEPTION(commodity_error, std::runtime_error);
class commodity_t class commodity_t
: public delegates_flags<>, : public delegates_flags<>,
public equality_comparable1<commodity_t, noncopyable> public equality_comparable1<commodity_t, noncopyable>
@ -63,13 +65,16 @@ public:
public: public:
typedef std::map<const datetime_t, amount_t> history_map; typedef std::map<const datetime_t, amount_t> history_map;
typedef std::pair<const datetime_t, amount_t> history_pair;
struct history_t { struct history_t {
history_map prices; history_map prices;
ptime last_lookup; 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_DEFAULTS 0x00
#define COMMODITY_STYLE_SUFFIXED 0x01 #define COMMODITY_STYLE_SUFFIXED 0x01
#define COMMODITY_STYLE_SEPARATED 0x02 #define COMMODITY_STYLE_SEPARATED 0x02
@ -82,7 +87,7 @@ public:
amount_t::precision_t precision; amount_t::precision_t precision;
optional<string> name; optional<string> name;
optional<string> note; optional<string> note;
optional<history_t> history; optional<varied_history_t> varied_history;
optional<amount_t> smaller; optional<amount_t> smaller;
optional<amount_t> larger; optional<amount_t> larger;
@ -102,8 +107,11 @@ public:
typedef base_t::history_t history_t; typedef base_t::history_t history_t;
typedef base_t::history_map history_map; typedef base_t::history_map history_map;
typedef base_t::varied_history_t varied_history_t;
typedef uint_least32_t ident_t; typedef uint_least32_t ident_t;
typedef base_t::history_by_commodity_map history_by_commodity_map;
shared_ptr<base_t> base; shared_ptr<base_t> base;
commodity_pool_t * parent_; commodity_pool_t * parent_;
@ -188,14 +196,30 @@ public:
base->larger = arg; base->larger = arg;
} }
optional<history_t> history() const { optional<varied_history_t&> varied_history() const {
return base->history; 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); 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 { struct cost_breakdown_t {
amount_t amount; amount_t amount;
@ -203,10 +227,6 @@ public:
amount_t basis_cost; 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, static cost_breakdown_t exchange(const amount_t& amount,
const amount_t& cost, const amount_t& cost,
const bool is_per_unit = false, const bool is_per_unit = false,