Did more restructing of commodity price histories, although the completed

find_price does not work yet.
This commit is contained in:
John Wiegley 2008-09-21 10:26:38 -04:00
parent 79a8fc5a87
commit 6007e3cbfe
3 changed files with 162 additions and 95 deletions

View file

@ -651,7 +651,7 @@ optional<amount_t> amount_t::value(const optional<datetime_t>& moment) const
{ {
if (quantity) { if (quantity) {
// jww (2008-09-21): 'none' is not the right argument here. // 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) if (amt)
return (*amt * number()).round(); return (*amt * number()).round();
} else { } else {

View file

@ -43,109 +43,75 @@
namespace ledger { namespace ledger {
optional<commodity_t::history_t&> void commodity_t::base_t::history_t::add_price(const datetime_t& date,
commodity_t::history(const optional<const commodity_t&>& commodity) const const amount_t& price)
{ {
if (base->varied_history) { history_map::iterator i = prices.find(date);
const commodity_t * comm = NULL; if (i != prices.end()) {
if (! commodity) { (*i).second = price;
if (base->varied_history->size() > 1) } else {
// jww (2008-09-20): Document which option switch to use here std::pair<history_map::iterator, bool> result
throw_(commodity_error, "Cannot determine history for '" = prices.insert(history_map::value_type(date, price));
<< *this << "': prices known for multiple commodities (use -?)"); assert(result.second);
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_t&> bool commodity_t::base_t::history_t::remove_price(const datetime_t& date)
commodity_t::history(const std::vector<const commodity_t *>& commodities) const
{ {
// This function differs from the single commodity case avoid in that history_map::size_type n = prices.erase(date);
// 'commodities' represents a list of preferred valuation commodities. if (n > 0)
// If no price can be located in terms of the first commodity, then return true;
// the second is chosen, etc. return false;
foreach (const commodity_t * commodity, commodities) {
if (optional<commodity_t::history_t&> hist =
history(*commodity))
return hist;
}
return none;
} }
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()); optional<history_t&> hist = history(price.commodity());
if (! hist) { if (! hist) {
std::pair<history_by_commodity_map::iterator, bool> result std::pair<history_by_commodity_map::iterator, bool> result
= base->varied_history->insert(history_by_commodity_map::value_type = histories.insert(history_by_commodity_map::value_type
(&price.commodity(), history_t())); (&price.commodity(), history_t()));
assert(result.second); assert(result.second);
hist = (*result.first).second; hist = (*result.first).second;
} }
assert(hist); assert(hist);
history_map::iterator i = hist->prices.find(date); hist->add_price(date, price);
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);
}
} }
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) { if (optional<history_t&> hist = history(comm))
optional<history_t&> hist = history(comm); return hist->remove_price(date);
if (hist) {
history_map::size_type n = hist->prices.erase(date);
if (n > 0) {
if (hist->prices.empty())
hist.reset();
return true;
}
}
}
return false; return false;
} }
optional<amount_t> optional<amount_t>
commodity_t::value(const history_t& history, commodity_t::base_t::history_t::find_price(const optional<datetime_t>& moment)
const optional<datetime_t>& moment)
{ {
optional<datetime_t> age; optional<datetime_t> age;
optional<amount_t> price; optional<amount_t> price;
if (history.prices.size() == 0) if (prices.size() == 0)
return none; return none;
if (! moment) { if (! moment) {
history_map::const_reverse_iterator r = history.prices.rbegin(); history_map::const_reverse_iterator r = prices.rbegin();
age = (*r).first; age = (*r).first;
price = (*r).second; price = (*r).second;
} else { } else {
history_map::const_iterator i = history.prices.lower_bound(*moment); history_map::const_iterator i = prices.lower_bound(*moment);
if (i == history.prices.end()) { if (i == prices.end()) {
history_map::const_reverse_iterator r = history.prices.rbegin(); history_map::const_reverse_iterator r = 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 != history.prices.begin()) { if (i != prices.begin()) {
--i; --i;
age = (*i).first; age = (*i).first;
price = (*i).second; price = (*i).second;
@ -171,6 +137,60 @@ commodity_t::value(const history_t& history,
return price; 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, void commodity_t::exchange(commodity_t& commodity,
const amount_t& per_unit_cost, const amount_t& per_unit_cost,
const datetime_t& moment) const datetime_t& moment)

View file

@ -66,14 +66,38 @@ public:
public: public:
typedef std::map<const datetime_t, amount_t> history_map; typedef std::map<const datetime_t, amount_t> history_map;
struct history_t { struct history_t
{
history_map prices; history_map prices;
ptime last_lookup; 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 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_DEFAULTS 0x00
#define COMMODITY_STYLE_SUFFIXED 0x01 #define COMMODITY_STYLE_SUFFIXED 0x01
@ -91,10 +115,12 @@ public:
optional<amount_t> smaller; optional<amount_t> smaller;
optional<amount_t> larger; optional<amount_t> larger;
mutable bool searched;
public: public:
explicit base_t(const string& _symbol) explicit base_t(const string& _symbol)
: supports_flags<>(COMMODITY_STYLE_DEFAULTS), : supports_flags<>(COMMODITY_STYLE_DEFAULTS),
symbol(_symbol), precision(0) { symbol(_symbol), precision(0), searched(false) {
TRACE_CTOR(base_t, "const string&"); TRACE_CTOR(base_t, "const string&");
} }
~base_t() { ~base_t() {
@ -196,40 +222,58 @@ public:
base->larger = arg; base->larger = arg;
} }
optional<varied_history_t&> varied_history() const { protected:
optional<varied_history_t&> varied_history() {
if (base->varied_history) if (base->varied_history)
return *base->varied_history; return *base->varied_history;
return none; return none;
} }
optional<history_t&> optional<history_t&>
history(const optional<const commodity_t&>& commodity) const; history(const optional<const commodity_t&>& commodity);
optional<history_t&> 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); optional<history_t>
bool remove_price(const datetime_t& date, const commodity_t& comm); find_price(const commodity_t& commodity,
const optional<datetime_t>& moment,
std::vector<bool *>& 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<amount_t> optional<amount_t>
value(const history_t& history, find_price(const optional<const commodity_t&>& commodity = none,
const optional<datetime_t>& moment = none); const optional<datetime_t>& moment = none) {
if (base->varied_history)
optional<amount_t> return base->varied_history->find_price(commodity, moment);
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);
return none; return none;
} }
optional<amount_t> optional<amount_t>
value(const std::vector<const commodity_t *>& commodities, find_price(const std::vector<const commodity_t *>& commodities,
const optional<datetime_t>& moment = none) { const optional<datetime_t>& moment = none) {
if (optional<history_t&> hist = history(commodities)) if (base->varied_history)
return value(*hist, moment); return base->varied_history->find_price(commodities, moment);
return none; return none;
} }
// Methods to exchange one commodity for another, while recording the
// factored price.
static void exchange(commodity_t& commodity, static void exchange(commodity_t& commodity,
const amount_t& per_unit_cost, const amount_t& per_unit_cost,
const datetime_t& moment); const datetime_t& moment);
@ -246,6 +290,9 @@ public:
const optional<datetime_t>& moment = none, const optional<datetime_t>& moment = none,
const optional<string>& tag = 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(std::istream& in, string& symbol);
static void parse_symbol(char *& p, string& symbol); static void parse_symbol(char *& p, string& symbol);
static string parse_symbol(std::istream& in) { static string parse_symbol(std::istream& in) {