summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/amount.cc2
-rw-r--r--src/commodity.cc152
-rw-r--r--src/commodity.h85
3 files changed, 153 insertions, 86 deletions
diff --git a/src/amount.cc b/src/amount.cc
index 59671f98..c052cd23 100644
--- a/src/amount.cc
+++ b/src/amount.cc
@@ -651,7 +651,7 @@ optional<amount_t> amount_t::value(const optional<datetime_t>& moment) const
{
if (quantity) {
// 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)
return (*amt * number()).round();
} else {
diff --git a/src/commodity.cc b/src/commodity.cc
index 11a53e96..f8ab523e 100644
--- a/src/commodity.cc
+++ b/src/commodity.cc
@@ -43,109 +43,75 @@
namespace ledger {
-optional<commodity_t::history_t&>
-commodity_t::history(const optional<const commodity_t&>& commodity) const
+void commodity_t::base_t::history_t::add_price(const datetime_t& date,
+ const amount_t& price)
{
- if (base->varied_history) {
- const commodity_t * comm = NULL;
- if (! commodity) {
- if (base->varied_history->size() > 1)
- // jww (2008-09-20): Document which option switch to use here
- throw_(commodity_error, "Cannot determine history for '"
- << *this << "': prices known for multiple commodities (use -?)");
- 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;
+ history_map::iterator i = prices.find(date);
+ if (i != prices.end()) {
+ (*i).second = price;
+ } else {
+ std::pair<history_map::iterator, bool> result
+ = prices.insert(history_map::value_type(date, price));
+ assert(result.second);
}
- return none;
}
-optional<commodity_t::history_t&>
-commodity_t::history(const std::vector<const commodity_t *>& commodities) const
+bool commodity_t::base_t::history_t::remove_price(const datetime_t& date)
{
- // 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<commodity_t::history_t&> hist =
- history(*commodity))
- return hist;
- }
- return none;
+ history_map::size_type n = prices.erase(date);
+ if (n > 0)
+ return true;
+ return false;
}
-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());
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()));
+ = histories.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
- = hist->prices.insert(history_map::value_type(date, price));
- assert(result.second);
- }
+
+ hist->add_price(date, price);
}
-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) {
- 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;
- }
- }
- }
+ if (optional<history_t&> hist = history(comm))
+ return hist->remove_price(date);
return false;
}
optional<amount_t>
-commodity_t::value(const history_t& history,
- const optional<datetime_t>& moment)
+commodity_t::base_t::history_t::find_price(const optional<datetime_t>& moment)
{
optional<datetime_t> age;
optional<amount_t> price;
- if (history.prices.size() == 0)
+ if (prices.size() == 0)
return none;
if (! moment) {
- history_map::const_reverse_iterator r = history.prices.rbegin();
+ history_map::const_reverse_iterator r = prices.rbegin();
age = (*r).first;
price = (*r).second;
} else {
- history_map::const_iterator i = history.prices.lower_bound(*moment);
- if (i == history.prices.end()) {
- history_map::const_reverse_iterator r = history.prices.rbegin();
+ history_map::const_iterator i = prices.lower_bound(*moment);
+ if (i == prices.end()) {
+ history_map::const_reverse_iterator r = prices.rbegin();
age = (*r).first;
price = (*r).second;
} else {
age = (*i).first;
if (*moment != *age) {
- if (i != history.prices.begin()) {
+ if (i != prices.begin()) {
--i;
age = (*i).first;
price = (*i).second;
@@ -171,6 +137,60 @@ commodity_t::value(const history_t& history,
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,
const amount_t& per_unit_cost,
const datetime_t& moment)
diff --git a/src/commodity.h b/src/commodity.h
index 6b1001cd..29011a7f 100644
--- a/src/commodity.h
+++ b/src/commodity.h
@@ -66,14 +66,38 @@ public:
public:
typedef std::map<const datetime_t, amount_t> history_map;
- struct history_t {
+ struct history_t
+ {
history_map prices;
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 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_SUFFIXED 0x01
@@ -91,10 +115,12 @@ public:
optional<amount_t> smaller;
optional<amount_t> larger;
+ mutable bool searched;
+
public:
explicit base_t(const string& _symbol)
: supports_flags<>(COMMODITY_STYLE_DEFAULTS),
- symbol(_symbol), precision(0) {
+ symbol(_symbol), precision(0), searched(false) {
TRACE_CTOR(base_t, "const string&");
}
~base_t() {
@@ -196,40 +222,58 @@ public:
base->larger = arg;
}
- optional<varied_history_t&> varied_history() const {
+protected:
+ optional<varied_history_t&> varied_history() {
if (base->varied_history)
return *base->varied_history;
return none;
}
optional<history_t&>
- history(const optional<const commodity_t&>& commodity) const;
+ history(const optional<const commodity_t&>& commodity);
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);
- bool remove_price(const datetime_t& date, const commodity_t& comm);
+ optional<history_t>
+ find_price(const commodity_t& commodity,
+ const optional<datetime_t>& moment,
+ std::vector<bool *>& bools);
- optional<amount_t>
- value(const history_t& history,
- const optional<datetime_t>& moment = none);
+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>
- 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);
+ find_price(const optional<const commodity_t&>& commodity = none,
+ const optional<datetime_t>& moment = none) {
+ if (base->varied_history)
+ return base->varied_history->find_price(commodity, moment);
return none;
}
optional<amount_t>
- value(const std::vector<const commodity_t *>& commodities,
- const optional<datetime_t>& moment = none) {
- if (optional<history_t&> hist = history(commodities))
- return value(*hist, moment);
+ find_price(const std::vector<const commodity_t *>& commodities,
+ const optional<datetime_t>& moment = none) {
+ if (base->varied_history)
+ return base->varied_history->find_price(commodities, moment);
return none;
}
+ // Methods to exchange one commodity for another, while recording the
+ // factored price.
+
static void exchange(commodity_t& commodity,
const amount_t& per_unit_cost,
const datetime_t& moment);
@@ -246,6 +290,9 @@ public:
const optional<datetime_t>& moment = 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(char *& p, string& symbol);
static string parse_symbol(std::istream& in) {