summaryrefslogtreecommitdiff
path: root/src/commodity.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/commodity.cc')
-rw-r--r--src/commodity.cc123
1 files changed, 82 insertions, 41 deletions
diff --git a/src/commodity.cc b/src/commodity.cc
index 7d473d74..8f0dc100 100644
--- a/src/commodity.cc
+++ b/src/commodity.cc
@@ -35,6 +35,7 @@
#include "commodity.h"
#include "annotate.h"
#include "pool.h"
+#include "scope.h"
namespace ledger {
@@ -70,12 +71,12 @@ void commodity_t::remove_price(const datetime_t& date, commodity_t& commodity)
}
void commodity_t::map_prices(function<void(datetime_t, const amount_t&)> fn,
- const optional<datetime_t>& moment,
- const optional<datetime_t>& _oldest)
+ const datetime_t& moment,
+ const datetime_t& _oldest)
{
datetime_t when;
- if (moment)
- when = *moment;
+ if (! moment.is_not_a_date_time())
+ when = moment;
else if (epoch)
when = *epoch;
else
@@ -85,78 +86,109 @@ void commodity_t::map_prices(function<void(datetime_t, const amount_t&)> fn,
}
optional<price_point_t>
-commodity_t::find_price(const optional<commodity_t&>& commodity,
- const optional<datetime_t>& moment,
- const optional<datetime_t>& oldest) const
+commodity_t::find_price_from_expr(expr_t& expr, const commodity_t * commodity,
+ const datetime_t& moment) const
{
- optional<commodity_t&> target;
+#if defined(DEBUG_ON)
+ if (SHOW_DEBUG("commodity.price.find")) {
+ ledger::_log_buffer << "valuation expr: ";
+ expr.dump(ledger::_log_buffer);
+ DEBUG("commodity.price.find", "");
+ }
+#endif
+ value_t result(expr.calc(*scope_t::default_scope));
+
+ if (is_expr(result)) {
+ value_t call_args;
+
+ call_args.push_back(string_value(base_symbol()));
+ call_args.push_back(moment);
+ if (commodity)
+ call_args.push_back(string_value(commodity->symbol()));
+
+ result = as_expr(result)->call(call_args, *scope_t::default_scope);
+ }
+
+ return price_point_t(moment, result.to_amount());
+}
+
+optional<price_point_t>
+commodity_t::find_price(const commodity_t * commodity,
+ const datetime_t& moment,
+ const datetime_t& oldest) const
+{
+ DEBUG("commodity.price.find", "commodity_t::find_price(" << symbol() << ")");
+
+ const commodity_t * target = NULL;
if (commodity)
target = commodity;
else if (pool().default_commodity)
- target = *pool().default_commodity;
+ target = &*pool().default_commodity;
- if (target && *this == *target)
+ if (target && this == target)
return none;
- optional<base_t::time_and_commodity_t> pair =
- base_t::time_and_commodity_t(base_t::optional_time_pair_t(moment, oldest),
- commodity ? &(*commodity) : NULL);
+ base_t::memoized_price_entry entry(moment, oldest,
+ commodity ? commodity : NULL);
- DEBUG("history.find", "looking for memoized args: "
- << (moment ? format_datetime(*moment) : "NONE") << ", "
- << (oldest ? format_datetime(*oldest) : "NONE") << ", "
+ DEBUG("commodity.price.find", "looking for memoized args: "
+ << (! moment.is_not_a_date_time() ? format_datetime(moment) : "NONE") << ", "
+ << (! oldest.is_not_a_date_time() ? format_datetime(oldest) : "NONE") << ", "
<< (commodity ? commodity->symbol() : "NONE"));
{
- base_t::memoized_price_map::iterator i = base->price_map.find(*pair);
+ base_t::memoized_price_map::iterator i = base->price_map.find(entry);
if (i != base->price_map.end()) {
- DEBUG("history.find", "found! returning: "
+ DEBUG("commodity.price.find", "found! returning: "
<< ((*i).second ? (*i).second->price : amount_t(0L)));
return (*i).second;
}
}
datetime_t when;
- if (moment)
- when = *moment;
+ if (! moment.is_not_a_date_time())
+ when = moment;
else if (epoch)
when = *epoch;
else
when = CURRENT_TIME();
- optional<price_point_t> point =
- target ?
- pool().commodity_price_history.find_price(*this, *target, when, oldest) :
- pool().commodity_price_history.find_price(*this, when, oldest);
-
- if (pair) {
- if (base->price_map.size() > base_t::max_price_map_size) {
- DEBUG("history.find",
- "price map has grown too large, clearing it by half");
- for (std::size_t i = 0; i < base_t::max_price_map_size >> 1; i++)
- base->price_map.erase(base->price_map.begin());
- }
+ if (base->value_expr)
+ return find_price_from_expr(*base->value_expr, commodity, when);
+ optional<price_point_t>
+ point(target ?
+ pool().commodity_price_history.find_price(*this, *target,
+ when, oldest) :
+ pool().commodity_price_history.find_price(*this, when, oldest));
+
+ // Record this price point in the memoization map
+ if (base->price_map.size() > base_t::max_price_map_size) {
DEBUG("history.find",
- "remembered: " << (point ? point->price : amount_t(0L)));
- base->price_map.insert
- (base_t::memoized_price_map::value_type(*pair, point));
+ "price map has grown too large, clearing it by half");
+ for (std::size_t i = 0; i < base_t::max_price_map_size >> 1; i++)
+ base->price_map.erase(base->price_map.begin());
}
+
+ DEBUG("history.find",
+ "remembered: " << (point ? point->price : amount_t(0L)));
+ base->price_map.insert(base_t::memoized_price_map::value_type(entry, point));
+
return point;
}
optional<price_point_t>
commodity_t::check_for_updated_price(const optional<price_point_t>& point,
- const optional<datetime_t>& moment,
- const optional<commodity_t&>& in_terms_of)
+ const datetime_t& moment,
+ const commodity_t* in_terms_of)
{
if (pool().get_quotes && ! has_flags(COMMODITY_NOMARKET)) {
bool exceeds_leeway = true;
if (point) {
time_duration_t::sec_type seconds_diff;
- if (moment) {
- seconds_diff = (*moment - point->when).total_seconds();
- DEBUG("commodity.download", "moment = " << *moment);
+ if (! moment.is_not_a_date_time()) {
+ seconds_diff = (moment - point->when).total_seconds();
+ DEBUG("commodity.download", "moment = " << moment);
DEBUG("commodity.download", "slip.moment = " << seconds_diff);
} else {
seconds_diff = (TRUE_CURRENT_TIME() - point->when).total_seconds();
@@ -175,7 +207,7 @@ commodity_t::check_for_updated_price(const optional<price_point_t>& point,
pool().get_commodity_quote(*this, in_terms_of)) {
if (! in_terms_of ||
(quote->price.has_commodity() &&
- quote->price.commodity() == *in_terms_of))
+ quote->price.commodity_ptr() == in_terms_of))
return quote;
}
}
@@ -183,6 +215,15 @@ commodity_t::check_for_updated_price(const optional<price_point_t>& point,
return point;
}
+commodity_t& commodity_t::nail_down(const expr_t& expr)
+{
+ annotation_t new_details;
+ new_details.value_expr = expr;
+ commodity_t * new_comm =
+ commodity_pool_t::current_pool->find_or_create(symbol(), new_details);
+ return *new_comm;
+}
+
commodity_t::operator bool() const
{
return this != pool().null_commodity;