summaryrefslogtreecommitdiff
path: root/src/commodity.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/commodity.cc')
-rw-r--r--src/commodity.cc203
1 files changed, 141 insertions, 62 deletions
diff --git a/src/commodity.cc b/src/commodity.cc
index 1b85910f..e45332b2 100644
--- a/src/commodity.cc
+++ b/src/commodity.cc
@@ -120,12 +120,16 @@ commodity_t::history_t::find_price(const optional<datetime_t>& moment,
price_point_t point;
bool found = false;
+#if defined(DEBUG_ON)
#define DEBUG_INDENT(cat, indent) \
do { \
if (SHOW_DEBUG(cat)) \
for (int i = 0; i < indent; i++) \
ledger::_log_buffer << " "; \
} while (false)
+#else
+#define DEBUG_INDENT(cat, indent)
+#endif
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent);
@@ -136,38 +140,34 @@ commodity_t::history_t::find_price(const optional<datetime_t>& moment,
if (oldest) {
DEBUG_INDENT("commodity.prices.find", indent);
- DEBUG("commodity.prices.find", " but no older than: " << *oldest);
+ DEBUG("commodity.prices.find", "but no older than: " << *oldest);
}
#endif
if (prices.size() == 0) {
-#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent);
- DEBUG("commodity.prices.find", " there are no prices in this history");
-#endif
+ DEBUG("commodity.prices.find", "there are no prices in this history");
return none;
}
if (! moment) {
history_map::const_reverse_iterator r = prices.rbegin();
- point.when = (*r).first;
+ point.when = (*r).first;
point.price = (*r).second;
found = true;
-#if defined(DEBUG_ON)
+
DEBUG_INDENT("commodity.prices.find", indent);
- DEBUG("commodity.prices.find", " using most recent price");
-#endif
+ DEBUG("commodity.prices.find", "using most recent price");
} else {
- history_map::const_iterator i = prices.lower_bound(*moment);
+ history_map::const_iterator i = prices.upper_bound(*moment);
if (i == prices.end()) {
history_map::const_reverse_iterator r = prices.rbegin();
point.when = (*r).first;
point.price = (*r).second;
found = true;
-#if defined(DEBUG_ON)
+
DEBUG_INDENT("commodity.prices.find", indent);
- DEBUG("commodity.prices.find", " using last price");
-#endif
+ DEBUG("commodity.prices.find", "using last price");
} else {
point.when = (*i).first;
if (*moment < point.when) {
@@ -181,40 +181,31 @@ commodity_t::history_t::find_price(const optional<datetime_t>& moment,
point.price = (*i).second;
found = true;
}
-#if defined(DEBUG_ON)
+
DEBUG_INDENT("commodity.prices.find", indent);
- DEBUG("commodity.prices.find", " using found price");
-#endif
+ DEBUG("commodity.prices.find", "using found price");
}
}
if (! found) {
-#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent);
- DEBUG("commodity.prices.find", " could not find a price");
-#endif
+ DEBUG("commodity.prices.find", "could not find a price");
return none;
}
else if (moment && point.when > *moment) {
-#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent);
- DEBUG("commodity.prices.find", " price is too young ");
-#endif
+ DEBUG("commodity.prices.find", "price is too young ");
return none;
}
else if (oldest && point.when < *oldest) {
-#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent);
- DEBUG("commodity.prices.find", " price is too old ");
-#endif
+ DEBUG("commodity.prices.find", "price is too old ");
return none;
}
else {
-#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find",
- " returning price: " << point.when << ", " << point.price);
-#endif
+ "returning price: " << point.when << ", " << point.price);
return point;
}
}
@@ -232,7 +223,13 @@ commodity_t::varied_history_t::find_price(const commodity_t& source,
optional<price_point_t> point;
optional<datetime_t> limit = oldest;
- assert(! commodity || source != *commodity);
+#if defined(VERIFY_ON)
+ if (commodity) {
+ VERIFY(source != *commodity);
+ VERIFY(! commodity->has_annotation());
+ VERIFY(source.referent() != commodity->referent());
+ }
+#endif
#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent);
@@ -240,18 +237,18 @@ commodity_t::varied_history_t::find_price(const commodity_t& source,
DEBUG_INDENT("commodity.prices.find", indent);
if (commodity)
- DEBUG("commodity.prices.find", " looking for: commodity '" << *commodity << "'");
+ DEBUG("commodity.prices.find", "looking for: commodity '" << *commodity << "'");
else
- DEBUG("commodity.prices.find", " looking for: any commodity");
+ DEBUG("commodity.prices.find", "looking for: any commodity");
if (moment) {
DEBUG_INDENT("commodity.prices.find", indent);
- DEBUG("commodity.prices.find", " time index: " << *moment);
+ DEBUG("commodity.prices.find", "time index: " << *moment);
}
if (oldest) {
DEBUG_INDENT("commodity.prices.find", indent);
- DEBUG("commodity.prices.find", " only consider prices younger than: " << *oldest);
+ DEBUG("commodity.prices.find", "only consider prices younger than: " << *oldest);
}
#endif
@@ -262,16 +259,18 @@ commodity_t::varied_history_t::find_price(const commodity_t& source,
price_point_t best;
bool found = false;
- foreach (history_by_commodity_map::value_type hist, histories) {
+ foreach (const history_by_commodity_map::value_type& hist, histories) {
commodity_t& comm(*hist.first);
if (comm == source)
continue;
-#if defined(DEBUG_ON)
+ // Only value secondary commodities in terms of primary ones
+ if (! commodity && ! comm.has_flags(COMMODITY_PRIMARY))
+ continue;
+
DEBUG_INDENT("commodity.prices.find", indent + 1);
DEBUG("commodity.prices.find",
- " searching for price via commodity '" << comm << "'");
-#endif
+ "searching for price via commodity '" << comm << "'");
point = hist.second.find_price(moment, limit
#if defined(DEBUG_ON)
@@ -284,68 +283,59 @@ commodity_t::varied_history_t::find_price(const commodity_t& source,
optional<price_point_t> xlat;
if (commodity && comm != *commodity) {
-#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent + 1);
- DEBUG("commodity.prices.find", " looking for translation price");
-#endif
+ DEBUG("commodity.prices.find", "looking for translation price");
- xlat = comm.find_price(commodity, moment, limit
+ xlat = comm.find_price(commodity, moment, limit, true
#if defined(DEBUG_ON)
, indent + 2
#endif
);
if (xlat) {
-#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent + 1);
- DEBUG("commodity.prices.find", " found translated price "
+ DEBUG("commodity.prices.find", "found translated price "
<< xlat->price << " from " << xlat->when);
-#endif
point->price = xlat->price * point->price;
if (xlat->when < point->when) {
point->when = xlat->when;
-#if defined(DEBUG_ON)
+
DEBUG_INDENT("commodity.prices.find", indent + 1);
DEBUG("commodity.prices.find",
- " adjusting date of result back to " << point->when);
-#endif
+ "adjusting date of result back to " << point->when);
}
} else {
-#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent + 1);
- DEBUG("commodity.prices.find", " saw no translated price there");
-#endif
+ DEBUG("commodity.prices.find", "saw no translated price there");
continue;
}
}
assert(! commodity || point->price.commodity() == *commodity);
-#if defined(DEBUG_ON)
+
DEBUG_INDENT("commodity.prices.find", indent + 1);
DEBUG("commodity.prices.find",
- " saw a price there: " << point->price << " from " << point->when);
-#endif
+ "saw a price there: " << point->price << " from " << point->when);
+
if (! limit || point->when > *limit) {
limit = point->when;
best = *point;
found = true;
+
+ DEBUG_INDENT("commodity.prices.find", indent + 1);
+ DEBUG("commodity.prices.find",
+ "search limit adjusted to " << *limit);
}
} else {
-#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent + 1);
- DEBUG("commodity.prices.find", " saw no price there");
-#endif
+ DEBUG("commodity.prices.find", "saw no price there");
}
}
if (found) {
-#if defined(DEBUG_ON)
DEBUG_INDENT("commodity.prices.find", indent);
- DEBUG("commodity.prices.find",
- " found price " << best.price << " from " << best.when);
DEBUG("commodity.download",
"found price " << best.price << " from " << best.when);
-#endif
return best;
}
return none;
@@ -371,6 +361,97 @@ commodity_t::varied_history_t::history(const optional<commodity_t&>& commodity)
}
optional<price_point_t>
+commodity_t::find_price(const optional<commodity_t&>& commodity,
+ const optional<datetime_t>& moment,
+ const optional<datetime_t>& oldest,
+ const bool nested
+#if defined(DEBUG_ON)
+ , const int indent
+#endif
+ ) const
+{
+ if (! has_flags(COMMODITY_WALKED) && base->varied_history &&
+ (commodity || ! has_flags(COMMODITY_PRIMARY))) {
+ optional<base_t::time_and_commodity_t> pair;
+#if defined(VERIFY_ON)
+ optional<price_point_t> checkpoint;
+ bool found = false;
+#endif
+
+ if (! nested) {
+ pair = base_t::time_and_commodity_t
+ (base_t::optional_time_pair_t(moment, oldest),
+ commodity ? &(*commodity) : NULL);
+ DEBUG_INDENT("commodity.prices.find", indent);
+ DEBUG("commodity.prices.find", "looking for memoized args: "
+ << (moment ? format_datetime(*moment) : "NONE") << ", "
+ << (oldest ? format_datetime(*oldest) : "NONE") << ", "
+ << (commodity ? commodity->symbol() : "NONE"));
+
+ base_t::memoized_price_map::iterator i = base->price_map.find(*pair);
+ if (i != base->price_map.end()) {
+ DEBUG_INDENT("commodity.prices.find", indent);
+ DEBUG("commodity.prices.find", "found! returning: "
+ << ((*i).second ? (*i).second->price : amount_t(0L)));
+#if defined(VERIFY_ON)
+ IF_VERIFY() {
+ found = true;
+ checkpoint = (*i).second;
+ } else
+#endif // defined(VERIFY_ON)
+ return (*i).second;
+ }
+ }
+
+ optional<price_point_t> point;
+
+ const_cast<commodity_t&>(*this).add_flags(COMMODITY_WALKED);
+ try {
+ DEBUG_INDENT("commodity.prices.find", indent);
+ DEBUG("commodity.prices.find", "manually finding price...");
+
+ point = base->varied_history->find_price(*this, commodity,
+ moment, oldest
+#if defined(DEBUG_ON)
+ , indent
+#endif
+ );
+ }
+ catch (...) {
+ const_cast<commodity_t&>(*this).drop_flags(COMMODITY_WALKED);
+ throw;
+ }
+ const_cast<commodity_t&>(*this).drop_flags(COMMODITY_WALKED);
+
+#if defined(VERIFY_ON)
+ if (DO_VERIFY() && found) {
+ VERIFY(checkpoint == point);
+ return checkpoint;
+ }
+#endif // defined(VERIFY_ON)
+
+ if (! nested && pair) {
+ if (base->price_map.size() > base_t::max_price_map_size) {
+ DEBUG_INDENT("commodity.prices.find", indent);
+ DEBUG("commodity.prices.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());
+ }
+
+ DEBUG_INDENT("commodity.prices.find", indent);
+ DEBUG("commodity.prices.find",
+ "remembered: " << (point ? point->price : amount_t(0L)));
+ base->price_map.insert
+ (base_t::memoized_price_map::value_type(*pair, point));
+ }
+ return point;
+ }
+ return none;
+}
+
+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)
@@ -428,9 +509,7 @@ namespace {
{
switch (buf[0]) {
case 'a':
- return (std::strcmp(buf, "and") == 0 ||
- std::strcmp(buf, "any") == 0 ||
- std::strcmp(buf, "all") == 0);
+ return std::strcmp(buf, "and") == 0;
case 'd':
return std::strcmp(buf, "div") == 0;
case 'e':