Did more restructing of commodity price histories, although the completed
find_price does not work yet.
This commit is contained in:
parent
79a8fc5a87
commit
6007e3cbfe
3 changed files with 162 additions and 95 deletions
|
|
@ -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 {
|
||||||
|
|
|
||||||
150
src/commodity.cc
150
src/commodity.cc
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue