From 3324e3472dcf5398350ba2dcd469207b8ceddd53 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Thu, 3 Jun 2010 00:54:10 -0400 Subject: [PATCH 01/26] Removed some debug code --- src/amount.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/amount.cc b/src/amount.cc index 9b7c3676..3bc6c871 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -149,10 +149,6 @@ namespace { mpfr_set_prec(tempfb, num_prec + den_prec); mpfr_div(tempfb, tempfnum, tempfden, GMP_RNDN); - char bigbuf[4096]; - mpfr_sprintf(bigbuf, "%.RNf", tempfb); - DEBUG("amount.convert", "num/den = " << bigbuf); - if (mpfr_asprintf(&buf, "%.*RNf", precision, tempfb) < 0) throw_(amount_error, _("Cannot output amount to a floating-point representation")); From 24b6afaf144a7ee43bc48bfd4cca8de863cb185c Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Thu, 3 Jun 2010 01:24:00 -0400 Subject: [PATCH 02/26] Preserve timestamp when copying objects from tools --- acprep | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/acprep b/acprep index e6da1869..78809f59 100755 --- a/acprep +++ b/acprep @@ -685,12 +685,16 @@ class PrepareBuild(CommandLineApp): self.current_version()) version_m4.close() + def copytimes(self, src, dest): + os.utime(dest, (os.stat(src)[ST_ATIME], os.stat(src)[ST_MTIME])) + def phase_autogen(self, *args): self.log.info('Executing phase: autogen') if not exists('autogen.sh') or \ self.isnewer('tools/autogen.sh', 'autogen.sh'): shutil.copyfile('tools/autogen.sh', 'autogen.sh') + self.copytimes('tools/autogen.sh', 'autogen.sh') self.execute('sh', 'tools/autogen.sh') @@ -704,10 +708,12 @@ class PrepareBuild(CommandLineApp): if not exists('configure.ac') or \ self.isnewer('tools/configure.ac', 'configure.ac'): shutil.copyfile('tools/configure.ac', 'configure.ac') + self.copytimes('tools/configure.ac', 'configure.ac') if not exists('Makefile.am') or \ self.isnewer('tools/Makefile.am', 'Makefile.am'): shutil.copyfile('tools/Makefile.am', 'Makefile.am') + self.copytimes('tools/Makefile.am', 'Makefile.am') reason = self.need_to_prepare_autotools() if reason: From 4a0236e964f5b39f38c3a8cd560bcfe6e4878912 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Thu, 3 Jun 2010 01:25:03 -0400 Subject: [PATCH 03/26] Updated tools/pre-commit --- tools/pre-commit | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tools/pre-commit b/tools/pre-commit index c049b8f0..50a32dbd 100755 --- a/tools/pre-commit +++ b/tools/pre-commit @@ -5,7 +5,7 @@ set -e # Exit if it's not a branch we're interested in being thorough about if echo $(git rev-parse --symbolic-full-name HEAD) | \ - egrep -q '^refs/heads/(next|t/)'; then + egrep -q '^refs/heads/(t/)'; then exit 0 fi @@ -41,12 +41,12 @@ cd $TMPDIR if [ ! -f Makefile -o \ Makefile.in -nt Makefile -o \ configure -nt Makefile -o \ - Makefile.am -nt Makefile.in -o \ - configure.ac -nt configure -o \ + tools/Makefile.am -nt Makefile.in -o \ + tools/configure.ac -nt configure -o \ \( -f acprep -a acprep -nt Makefile \) ] then if [ -f acprep ]; then - ./acprep default --local + echo Will run acprep in a moment elif [ -f autogen.sh ]; then sh autogen.sh && ./configure else @@ -56,6 +56,10 @@ fi # Finally, (re)build this proposed source tree and see if it passes # muster. -nice -n 20 make check +if [ -f acprep ]; then + nice -n 20 ./acprep default --warn make check +else + nice -n 20 make check +fi exit 0 From 30479c0e1283201f905e2129970ad4784c9c5ba2 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Thu, 3 Jun 2010 01:26:30 -0400 Subject: [PATCH 04/26] A simple, yet significiant, optimization Every annotated commodity is based on a "referent", or the unannotated version of that commodity. When stripping all annotations away, however, rather than simply returning the referent we were actually searching for it by name. There was no reason to do this, not to mention it was taking up to 7% of the total runtime of some reports. --- src/annotate.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/annotate.cc b/src/annotate.cc index 99c12fc3..feb3b3ca 100644 --- a/src/annotate.cc +++ b/src/annotate.cc @@ -190,7 +190,7 @@ annotated_commodity_t::strip_annotations(const keep_details_t& what_to_keep) keep_date ? details.date : none, keep_tag ? details.tag : none)); } else { - new_comm = pool().find_or_create(base_symbol()); + new_comm = &referent(); } assert(new_comm); From 3a0f096cb64f581f0d8513c8b67ca41659982afa Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Thu, 3 Jun 2010 05:37:21 -0400 Subject: [PATCH 05/26] Added new "addr" value expression function It returns the address of the given object as an integer. This can be used to uniquely compare entities. --- src/account.cc | 6 ++++++ src/item.cc | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/account.cc b/src/account.cc index 8d4341e7..e577c48e 100644 --- a/src/account.cc +++ b/src/account.cc @@ -218,6 +218,10 @@ namespace { return true; } + value_t get_addr(account_t& account) { + return long(&account); + } + value_t get_depth_spacer(account_t& account) { std::size_t depth = 0; @@ -296,6 +300,8 @@ expr_t::ptr_op_t account_t::lookup(const symbol_t::kind_t kind, return WRAP_FUNCTOR(get_wrapper<&get_account>); else if (name == "account_base") return WRAP_FUNCTOR(get_wrapper<&get_account_base>); + else if (name == "addr") + return WRAP_FUNCTOR(get_wrapper<&get_addr>); else if (name == "any") return WRAP_FUNCTOR(&fn_any); else if (name == "all") diff --git a/src/item.cc b/src/item.cc index 0a22b260..fea73066 100644 --- a/src/item.cc +++ b/src/item.cc @@ -323,6 +323,10 @@ namespace { return item.pos ? long(item.pos->sequence) : 0L; } + value_t get_addr(item_t& item) { + return long(&item); + } + value_t get_depth(item_t&) { return 0L; } @@ -376,6 +380,8 @@ expr_t::ptr_op_t item_t::lookup(const symbol_t::kind_t kind, return WRAP_FUNCTOR(get_wrapper<&get_actual>); else if (name == "actual_date") return WRAP_FUNCTOR(get_wrapper<&get_actual_date>); + else if (name == "addr") + return WRAP_FUNCTOR(get_wrapper<&get_addr>); break; case 'b': From 0f1afdb3a7387e834c62b4ecc0a993bdde62d8f8 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Thu, 3 Jun 2010 05:47:12 -0400 Subject: [PATCH 06/26] Minor optimization of amount_t::operator* --- src/amount.cc | 28 ++++++++++++++++++---------- src/amount.h | 5 ++++- test/regress/25A099C9.test | 12 ++++++------ 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/amount.cc b/src/amount.cc index 3bc6c871..bcd4bb8c 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -468,7 +468,7 @@ amount_t& amount_t::operator-=(const amount_t& amt) return *this; } -amount_t& amount_t::operator*=(const amount_t& amt) +amount_t& amount_t::multiply(const amount_t& amt, bool ignore_commodity) { VERIFY(amt.valid()); @@ -487,7 +487,7 @@ amount_t& amount_t::operator*=(const amount_t& amt) quantity->prec = static_cast(quantity->prec + amt.quantity->prec); - if (! has_commodity()) + if (! has_commodity() && ! ignore_commodity) commodity_ = amt.commodity_; if (has_commodity() && ! keep_precision()) { @@ -742,19 +742,27 @@ amount_t::value(const bool primary_only, } else if (has_annotation() && annotation().price && annotation().has_flags(ANNOTATION_PRICE_FIXATED)) { - return (*annotation().price * number()).rounded(); + amount_t price(*annotation().price); + price.multiply(*this, true); + price.in_place_round(); + return price; } else { optional point = commodity().find_price(in_terms_of, moment); - // Whether a price was found or not, check whether we should attempt - // to download a price from the Internet. This is done if (a) no - // price was found, or (b) the price is "stale" according to the - // setting of --price-exp. - point = commodity().check_for_updated_price(point, moment, in_terms_of); - if (point) - return (point->price * number()).rounded(); + // Whether a price was found or not, check whether we should + // attempt to download a price from the Internet. This is done + // if (a) no price was found, or (b) the price is "stale" + // according to the setting of --price-exp. + point = commodity().check_for_updated_price(point, moment, + in_terms_of); + if (point) { + amount_t price(point->price); + price.multiply(*this, true); + price.in_place_round(); + return price; + } } } } else { diff --git a/src/amount.h b/src/amount.h index ae0e5a69..1ac4b37e 100644 --- a/src/amount.h +++ b/src/amount.h @@ -275,7 +275,10 @@ public: amount_t& operator+=(const amount_t& amt); amount_t& operator-=(const amount_t& amt); - amount_t& operator*=(const amount_t& amt); + amount_t& operator*=(const amount_t& amt) { + return multiply(amt); + } + amount_t& multiply(const amount_t& amt, bool ignore_commodity = false); /** Divide two amounts while extending the precision to preserve the accuracy of the result. For example, if \c 10 is divided by \c 3, diff --git a/test/regress/25A099C9.test b/test/regress/25A099C9.test index a74b0601..604939d8 100644 --- a/test/regress/25A099C9.test +++ b/test/regress/25A099C9.test @@ -4,16 +4,16 @@ >>>2 While parsing file "$sourcepath/src/amount.h", line 67: Error: No quantity specified for amount -While parsing file "$sourcepath/src/amount.h", line 718: +While parsing file "$sourcepath/src/amount.h", line 721: Error: Invalid date/time: line amount_t amoun -While parsing file "$sourcepath/src/amount.h", line 724: +While parsing file "$sourcepath/src/amount.h", line 727: Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/src/amount.h", line 730: +While parsing file "$sourcepath/src/amount.h", line 733: Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/src/amount.h", line 736: +While parsing file "$sourcepath/src/amount.h", line 739: Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/src/amount.h", line 742: +While parsing file "$sourcepath/src/amount.h", line 745: Error: Invalid date/time: line std::ostream& -While parsing file "$sourcepath/src/amount.h", line 749: +While parsing file "$sourcepath/src/amount.h", line 752: Error: Invalid date/time: line std::istream& === 7 From c3cc935ba6f22f580518fd8858fbe424f2842f31 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Thu, 3 Jun 2010 17:35:47 -0400 Subject: [PATCH 07/26] For 'acprep opt' enable NDEBUG for even more speed --- acprep | 1 + 1 file changed, 1 insertion(+) diff --git a/acprep b/acprep index 78809f59..87e2cd64 100755 --- a/acprep +++ b/acprep @@ -1165,6 +1165,7 @@ class PrepareBuild(CommandLineApp): self.LDFLAGS.append('-g') def setup_flavor_opt(self): + self.CPPFLAGS.append('-DNDEBUG=1') if self.darwin_gcc: self.option_no_pch() if '--disable-shared' in self.configure_args: From 27b86a5388a9b1a5d5c748fa7e6f8aa4a2f1a3f4 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Thu, 3 Jun 2010 17:43:38 -0400 Subject: [PATCH 08/26] Avoid unnecessary object copying when using foreach --- src/commodity.cc | 2 +- src/filters.cc | 6 +++--- src/iterators.cc | 4 ++-- src/pool.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/commodity.cc b/src/commodity.cc index 1b85910f..a1c26403 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -262,7 +262,7 @@ 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; diff --git a/src/filters.cc b/src/filters.cc index ad4b88a0..70a46e8e 100644 --- a/src/filters.cc +++ b/src/filters.cc @@ -50,7 +50,7 @@ void post_splitter::print_title(const value_t& val) void post_splitter::flush() { - foreach (value_to_posts_map::value_type pair, posts_map) { + foreach (value_to_posts_map::value_type& pair, posts_map) { preflush_func(pair.first); foreach (post_t * post, pair.second) @@ -894,7 +894,7 @@ void posts_as_equity::report_subtotal() value_t total = 0L; foreach (values_map::value_type& pair, values) { if (pair.second.value.is_balance()) { - foreach (balance_t::amounts_map::value_type amount_pair, + foreach (const balance_t::amounts_map::value_type& amount_pair, pair.second.value.as_balance().amounts) handle_value(amount_pair.second, pair.second.account, &xact, temps, handler); @@ -907,7 +907,7 @@ void posts_as_equity::report_subtotal() values.clear(); if (total.is_balance()) { - foreach (balance_t::amounts_map::value_type pair, + foreach (const balance_t::amounts_map::value_type& pair, total.as_balance().amounts) { post_t& balance_post = temps.create_post(xact, balance_account); balance_post.amount = - pair.second; diff --git a/src/iterators.cc b/src/iterators.cc index f3a68978..ade1d4b3 100644 --- a/src/iterators.cc +++ b/src/iterators.cc @@ -94,9 +94,9 @@ void posts_commodities_iterator::reset(journal_t& journal) comm->varied_history()) { account_t * account = journal.master->find_account(comm->symbol()); - foreach (commodity_t::history_by_commodity_map::value_type pair, + foreach (commodity_t::history_by_commodity_map::value_type& pair, history->histories) { - foreach (commodity_t::history_map::value_type hpair, + foreach (commodity_t::history_map::value_type& hpair, pair.second.prices) { xact_t * xact; string symbol = hpair.second.commodity().symbol(); diff --git a/src/pool.h b/src/pool.h index 915def16..c1325944 100644 --- a/src/pool.h +++ b/src/pool.h @@ -86,7 +86,7 @@ public: virtual ~commodity_pool_t() { TRACE_DTOR(commodity_pool_t); - foreach (commodities_map::value_type pair, commodities) + foreach (commodities_map::value_type& pair, commodities) checked_delete(pair.second); } From e6c5837b2ca85363b9dc5255592ca5e9da8900e1 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Thu, 3 Jun 2010 17:57:09 -0400 Subject: [PATCH 09/26] Corrected a debug statement --- src/pool.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/pool.cc b/src/pool.cc index 8d9f0c28..6b422351 100644 --- a/src/pool.cc +++ b/src/pool.cc @@ -122,8 +122,11 @@ string commodity_pool_t::make_qualified_name(const commodity_t& comm, comm.print(name); details.print(name, comm.pool().keep_base); - DEBUG("amounts.commodities", "make_qualified_name for " - << *comm.qualified_symbol << std::endl << details); +#if defined(DEBUG_ON) + if (comm.qualified_symbol) + DEBUG("amounts.commodities", "make_qualified_name for " + << *comm.qualified_symbol << std::endl << details); +#endif DEBUG("amounts.commodities", "qualified_name is " << name.str()); return name.str(); From e8bf3da053e7e1aa2aae01f179d94be414a62ff1 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Thu, 3 Jun 2010 17:59:43 -0400 Subject: [PATCH 10/26] Short-circuit annotated commodity valuation --- src/amount.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/amount.cc b/src/amount.cc index bcd4bb8c..d9b7c82c 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -737,7 +737,9 @@ amount_t::value(const bool primary_only, #endif if (has_commodity() && (! primary_only || ! commodity().has_flags(COMMODITY_PRIMARY))) { - if (in_terms_of && commodity() == *in_terms_of) { + if (in_terms_of && + (commodity() == *in_terms_of || + commodity().referent() == in_terms_of->referent())) { return *this; } else if (has_annotation() && annotation().price && From f76b271d24f1464d33bbd05e4e7e14c2c80ee3e7 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Thu, 3 Jun 2010 23:18:18 -0400 Subject: [PATCH 11/26] Removed a redundant check --- src/amount.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/amount.cc b/src/amount.cc index d9b7c82c..2837178c 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -738,8 +738,7 @@ amount_t::value(const bool primary_only, if (has_commodity() && (! primary_only || ! commodity().has_flags(COMMODITY_PRIMARY))) { if (in_terms_of && - (commodity() == *in_terms_of || - commodity().referent() == in_terms_of->referent())) { + commodity().referent() == in_terms_of->referent()) { return *this; } else if (has_annotation() && annotation().price && From 45451125e329f47314e24b34425f6da3aab920cd Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Thu, 3 Jun 2010 23:23:12 -0400 Subject: [PATCH 12/26] Simplified some debug code --- src/commodity.cc | 49 ++++++++++++++++-------------------------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/src/commodity.cc b/src/commodity.cc index a1c26403..b1cdfdb4 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -120,12 +120,16 @@ commodity_t::history_t::find_price(const optional& 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); @@ -141,10 +145,8 @@ commodity_t::history_t::find_price(const optional& moment, #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 return none; } @@ -153,10 +155,9 @@ commodity_t::history_t::find_price(const optional& moment, 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 } else { history_map::const_iterator i = prices.lower_bound(*moment); if (i == prices.end()) { @@ -164,10 +165,9 @@ commodity_t::history_t::find_price(const optional& moment, 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 } else { point.when = (*i).first; if (*moment < point.when) { @@ -181,40 +181,31 @@ commodity_t::history_t::find_price(const optional& 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 } } if (! found) { -#if defined(DEBUG_ON) DEBUG_INDENT("commodity.prices.find", indent); DEBUG("commodity.prices.find", " could not find a price"); -#endif 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 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 return none; } else { -#if defined(DEBUG_ON) DEBUG_INDENT("commodity.prices.find", indent); DEBUG("commodity.prices.find", " returning price: " << point.when << ", " << point.price); -#endif return point; } } @@ -232,7 +223,13 @@ commodity_t::varied_history_t::find_price(const commodity_t& source, optional point; optional 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); @@ -267,11 +264,9 @@ commodity_t::varied_history_t::find_price(const commodity_t& source, if (comm == source) continue; -#if defined(DEBUG_ON) DEBUG_INDENT("commodity.prices.find", indent + 1); DEBUG("commodity.prices.find", " searching for price via commodity '" << comm << "'"); -#endif point = hist.second.find_price(moment, limit #if defined(DEBUG_ON) @@ -284,10 +279,8 @@ commodity_t::varied_history_t::find_price(const commodity_t& source, optional 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 xlat = comm.find_price(commodity, moment, limit #if defined(DEBUG_ON) @@ -295,57 +288,47 @@ commodity_t::varied_history_t::find_price(const commodity_t& source, #endif ); if (xlat) { -#if defined(DEBUG_ON) DEBUG_INDENT("commodity.prices.find", indent + 1); 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 } } else { -#if defined(DEBUG_ON) DEBUG_INDENT("commodity.prices.find", indent + 1); DEBUG("commodity.prices.find", " saw no translated price there"); -#endif 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 + if (! limit || point->when > *limit) { limit = point->when; best = *point; found = true; } } else { -#if defined(DEBUG_ON) DEBUG_INDENT("commodity.prices.find", indent + 1); DEBUG("commodity.prices.find", " saw no price there"); -#endif } } 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; From 946534b102da5bd9bc1e26e1c0f3869dc81457d7 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Fri, 4 Jun 2010 02:23:04 -0400 Subject: [PATCH 13/26] A little bit of code cleanup --- src/amount.h | 3 +-- src/commodity.h | 1 + src/report.cc | 30 ++++++++++++++++++++---------- src/session.h | 1 - test/regress/25A099C9.test | 14 +++++++------- 5 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/amount.h b/src/amount.h index 1ac4b37e..49f33417 100644 --- a/src/amount.h +++ b/src/amount.h @@ -62,7 +62,6 @@ namespace ledger { class commodity_t; class annotation_t; class keep_details_t; -class commodity_pool_t; DECLARE_EXCEPTION(amount_error, std::runtime_error); @@ -514,7 +513,7 @@ public: amount's commodity: commodity() returns an amount's commodity. If the amount has no - commodity, the value returned is `current_pool->null_commodity'. + commodity, the value returned is the `null_commodity'. has_commodity() returns true if the amount has a commodity. diff --git a/src/commodity.h b/src/commodity.h index 53e3033f..05dc3395 100644 --- a/src/commodity.h +++ b/src/commodity.h @@ -50,6 +50,7 @@ namespace ledger { class keep_details_t; +class commodity_pool_t; DECLARE_EXCEPTION(commodity_error, std::runtime_error); diff --git a/src/report.cc b/src/report.cc index cc652f8d..81234b0f 100644 --- a/src/report.cc +++ b/src/report.cc @@ -1318,9 +1318,10 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, case symbol_t::COMMAND: switch (*p) { case 'a': - if (is_eq(p, "accounts")) + if (is_eq(p, "accounts")) { return WRAP_FUNCTOR(reporter<>(new report_accounts(*this), *this, "#accounts")); + } break; case 'b': @@ -1381,48 +1382,57 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, HANDLER(print_virtual).on_only(string("#equity")); return WRAP_FUNCTOR(reporter<>(new print_xacts(*this), *this, "#equity")); } - else if (is_eq(p, "entry")) + else if (is_eq(p, "entry")) { return WRAP_FUNCTOR(xact_command); - else if (is_eq(p, "emacs")) + } + else if (is_eq(p, "emacs")) { return WRAP_FUNCTOR (reporter<>(new format_emacs_posts(output_stream), *this, "#emacs")); - else if (is_eq(p, "echo")) + } + else if (is_eq(p, "echo")) { return MAKE_FUNCTOR(report_t::echo_command); + } break; case 'p': - if (*(p + 1) == '\0' || is_eq(p, "print")) + if (*(p + 1) == '\0' || is_eq(p, "print")) { return WRAP_FUNCTOR (reporter<>(new print_xacts(*this, HANDLED(raw)), *this, "#print")); - else if (is_eq(p, "prices")) + } + else if (is_eq(p, "prices")) { return expr_t::op_t::wrap_functor (reporter (new format_posts(*this, report_format(HANDLER(prices_format_)), maybe_format(HANDLER(prepend_format_)), HANDLER(prepend_width_).value.to_long()), *this, "#prices")); - else if (is_eq(p, "pricedb")) + } + else if (is_eq(p, "pricedb")) { return expr_t::op_t::wrap_functor (reporter (new format_posts(*this, report_format(HANDLER(pricedb_format_)), maybe_format(HANDLER(prepend_format_)), HANDLER(prepend_width_).value.to_long()), *this, "#pricedb")); - else if (is_eq(p, "payees")) + } + else if (is_eq(p, "payees")) { return WRAP_FUNCTOR(reporter<>(new report_payees(*this), *this, "#payees")); + } break; case 'r': - if (*(p + 1) == '\0' || is_eq(p, "reg") || is_eq(p, "register")) + if (*(p + 1) == '\0' || is_eq(p, "reg") || is_eq(p, "register")) { return WRAP_FUNCTOR (reporter<> (new format_posts(*this, report_format(HANDLER(register_format_)), maybe_format(HANDLER(prepend_format_)), HANDLER(prepend_width_).value.to_long()), *this, "#register")); - else if (is_eq(p, "reload")) + } + else if (is_eq(p, "reload")) { return MAKE_FUNCTOR(report_t::reload_command); + } break; case 's': diff --git a/src/session.h b/src/session.h index 10f636bb..3916b964 100644 --- a/src/session.h +++ b/src/session.h @@ -50,7 +50,6 @@ namespace ledger { -class commodity_pool_t; class xact_t; class session_t : public symbol_scope_t diff --git a/test/regress/25A099C9.test b/test/regress/25A099C9.test index 604939d8..251b0f24 100644 --- a/test/regress/25A099C9.test +++ b/test/regress/25A099C9.test @@ -2,18 +2,18 @@ <<< >>>1 >>>2 -While parsing file "$sourcepath/src/amount.h", line 67: +While parsing file "$sourcepath/src/amount.h", line 66: Error: No quantity specified for amount -While parsing file "$sourcepath/src/amount.h", line 721: +While parsing file "$sourcepath/src/amount.h", line 720: Error: Invalid date/time: line amount_t amoun -While parsing file "$sourcepath/src/amount.h", line 727: +While parsing file "$sourcepath/src/amount.h", line 726: Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/src/amount.h", line 733: +While parsing file "$sourcepath/src/amount.h", line 732: Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/src/amount.h", line 739: +While parsing file "$sourcepath/src/amount.h", line 738: Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/src/amount.h", line 745: +While parsing file "$sourcepath/src/amount.h", line 744: Error: Invalid date/time: line std::ostream& -While parsing file "$sourcepath/src/amount.h", line 752: +While parsing file "$sourcepath/src/amount.h", line 751: Error: Invalid date/time: line std::istream& === 7 From dbac09405f1dede27d21f91dddc991f76e0f7438 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Fri, 4 Jun 2010 02:52:36 -0400 Subject: [PATCH 14/26] Added new command: "pricemap [DATE]" This outputs the pricing relationship of commodities in your data file, as of DATE (optional), using the DOT language. If you have graphviz installed, it can be viewed quite simply using: ledger pricemap | dotty - Each relationship in the graph shows the conversion factor to exchange one commodity for another, and the date at which this factor was determined. --- src/pool.cc | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/pool.h | 6 +++++ src/report.cc | 15 +++++++++++ src/report.h | 1 + 4 files changed, 94 insertions(+) diff --git a/src/pool.cc b/src/pool.cc index 6b422351..ad97a9c6 100644 --- a/src/pool.cc +++ b/src/pool.cc @@ -364,4 +364,76 @@ commodity_pool_t::parse_price_expression(const std::string& str, return NULL; } +void commodity_pool_t::print_pricemap(std::ostream& out, + const keep_details_t& keep, + const optional& moment) +{ + typedef std::map comm_map_t; + + comm_map_t comm_map; + + foreach (const commodities_map::value_type& comm_pair, commodities) { + commodity_t * comm(&comm_pair.second->strip_annotations(keep)); + comm_map.insert(comm_map_t::value_type(comm, NULL)); + } + + out << "digraph commodities {\n"; + + foreach (const comm_map_t::value_type& comm_pair, comm_map) { + commodity_t * comm(comm_pair.first); + if (comm->has_flags(COMMODITY_BUILTIN)) + continue; + + out << " "; + if (commodity_t::symbol_needs_quotes(comm->symbol())) + out << comm->symbol() << ";\n"; + else + out << "\"" << comm->symbol() << "\";\n"; + + if (! comm->has_flags(COMMODITY_NOMARKET) && + (! commodity_pool_t::current_pool->default_commodity || + comm != commodity_pool_t::current_pool->default_commodity)) { + if (optional vhist = + comm->varied_history()) { + foreach (const commodity_t::history_by_commodity_map::value_type& pair, + vhist->histories) { + datetime_t most_recent; + amount_t most_recent_amt; + foreach (const commodity_t::history_map::value_type& inner_pair, + pair.second.prices) { + if ((most_recent.is_not_a_date_time() || + inner_pair.first > most_recent) && + (! moment || inner_pair.first <= moment)) { + most_recent = inner_pair.first; + most_recent_amt = inner_pair.second; + } + } + + if (! most_recent.is_not_a_date_time()) { + out << " "; + if (commodity_t::symbol_needs_quotes(comm->symbol())) + out << comm->symbol(); + else + out << "\"" << comm->symbol() << "\""; + + out << " -> "; + + if (commodity_t::symbol_needs_quotes(pair.first->symbol())) + out << pair.first->symbol(); + else + out << "\"" << pair.first->symbol() << "\""; + + out << " [label=\"" + << most_recent_amt.number() << "\\n" + << format_date(most_recent.date(), FMT_WRITTEN) + << "\" fontcolor=\"#008e28\"];\n"; + } + } + } + } + } + + out << "}\n"; +} + } // namespace ledger diff --git a/src/pool.h b/src/pool.h index c1325944..ac66d7a6 100644 --- a/src/pool.h +++ b/src/pool.h @@ -131,6 +131,12 @@ public: const bool add_prices = true, const optional& moment = none); + // Output the commodity price map for a given date as a DOT file + + void print_pricemap(std::ostream& out, + const keep_details_t& keep, + const optional& moment = none); + #if defined(HAVE_BOOST_SERIALIZATION) private: /** Serialization. */ diff --git a/src/report.cc b/src/report.cc index 81234b0f..e51736fd 100644 --- a/src/report.cc +++ b/src/report.cc @@ -842,6 +842,18 @@ value_t report_t::echo_command(call_scope_t& scope) return true; } +value_t report_t::pricemap_command(call_scope_t& scope) +{ + interactive_t args(scope, "&s"); + std::ostream& out(output_stream); + + commodity_pool_t::current_pool->print_pricemap + (out, what_to_keep(), args.has(0) ? + optional(datetime_t(parse_date(args.get(0)))) : none); + + return true; +} + option_t * report_t::lookup_option(const char * p) { switch (*p) { @@ -1415,6 +1427,9 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, HANDLER(prepend_width_).value.to_long()), *this, "#pricedb")); } + else if (is_eq(p, "pricemap")) { + return MAKE_FUNCTOR(report_t::pricemap_command); + } else if (is_eq(p, "payees")) { return WRAP_FUNCTOR(reporter<>(new report_payees(*this), *this, "#payees")); diff --git a/src/report.h b/src/report.h index 6fa238f0..99b8781b 100644 --- a/src/report.h +++ b/src/report.h @@ -198,6 +198,7 @@ public: value_t reload_command(call_scope_t&); value_t echo_command(call_scope_t& scope); + value_t pricemap_command(call_scope_t& scope); keep_details_t what_to_keep() { bool lots = HANDLED(lots) || HANDLED(lots_actual); From 2ae2dc86c6bf88f512f905ff3b9ed9c170baf536 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Fri, 4 Jun 2010 02:54:38 -0400 Subject: [PATCH 15/26] Reorganized some debug code --- src/commodity.cc | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/commodity.cc b/src/commodity.cc index b1cdfdb4..7aecc2bb 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -235,20 +235,20 @@ commodity_t::varied_history_t::find_price(const commodity_t& source, DEBUG_INDENT("commodity.prices.find", indent); DEBUG("commodity.prices.find", "varied_find_price for: " << source); - DEBUG_INDENT("commodity.prices.find", indent); + DEBUG_INDENT("commodity.prices.find", indent + 1); 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_INDENT("commodity.prices.find", indent + 1); + 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_INDENT("commodity.prices.find", indent + 1); + DEBUG("commodity.prices.find", "only consider prices younger than: " << *oldest); } #endif @@ -266,7 +266,7 @@ commodity_t::varied_history_t::find_price(const commodity_t& source, DEBUG_INDENT("commodity.prices.find", indent + 1); DEBUG("commodity.prices.find", - " searching for price via commodity '" << comm << "'"); + "searching for price via commodity '" << comm << "'"); point = hist.second.find_price(moment, limit #if defined(DEBUG_ON) @@ -280,7 +280,7 @@ commodity_t::varied_history_t::find_price(const commodity_t& source, if (commodity && comm != *commodity) { DEBUG_INDENT("commodity.prices.find", indent + 1); - DEBUG("commodity.prices.find", " looking for translation price"); + DEBUG("commodity.prices.find", "looking for translation price"); xlat = comm.find_price(commodity, moment, limit #if defined(DEBUG_ON) @@ -289,7 +289,7 @@ commodity_t::varied_history_t::find_price(const commodity_t& source, ); if (xlat) { 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); point->price = xlat->price * point->price; @@ -298,35 +298,38 @@ commodity_t::varied_history_t::find_price(const commodity_t& source, DEBUG_INDENT("commodity.prices.find", indent + 1); DEBUG("commodity.prices.find", - " adjusting date of result back to " << point->when); + "adjusting date of result back to " << point->when); } } else { DEBUG_INDENT("commodity.prices.find", indent + 1); - DEBUG("commodity.prices.find", " saw no translated price there"); + DEBUG("commodity.prices.find", "saw no translated price there"); continue; } } assert(! commodity || point->price.commodity() == *commodity); + DEBUG_INDENT("commodity.prices.find", indent + 1); DEBUG("commodity.prices.find", - " saw a price there: " << point->price << " from " << point->when); + "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 { DEBUG_INDENT("commodity.prices.find", indent + 1); - DEBUG("commodity.prices.find", " saw no price there"); + DEBUG("commodity.prices.find", "saw no price there"); } } if (found) { - DEBUG_INDENT("commodity.prices.find", indent); - DEBUG("commodity.prices.find", - " found price " << best.price << " from " << best.when); + DEBUG_INDENT("commodity.prices.find", indent + 1); DEBUG("commodity.download", "found price " << best.price << " from " << best.when); return best; From 7f7243ff9360f1c44f9e7b16a0e93244645aa031 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Fri, 4 Jun 2010 03:11:14 -0400 Subject: [PATCH 16/26] Made the behavior of -V a bit more rational It now only values non-primary commodities in terms of primary ones. --- src/commodity.cc | 4 ++++ src/commodity.h | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/commodity.cc b/src/commodity.cc index 7aecc2bb..61fd0fe5 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -264,6 +264,10 @@ commodity_t::varied_history_t::find_price(const commodity_t& source, if (comm == source) continue; + // 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 << "'"); diff --git a/src/commodity.h b/src/commodity.h index 05dc3395..483d98b0 100644 --- a/src/commodity.h +++ b/src/commodity.h @@ -351,7 +351,8 @@ public: , const int indent = 0 #endif ) const { - if (base->varied_history && ! has_flags(COMMODITY_WALKED)) { + if (! has_flags(COMMODITY_WALKED) && base->varied_history && + (commodity || ! has_flags(COMMODITY_PRIMARY))) { const_cast(*this).add_flags(COMMODITY_WALKED); optional point = base->varied_history->find_price(*this, commodity, moment, oldest From b7e8cb9d544af0f054093092afa4d0820aa4a453 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Fri, 4 Jun 2010 03:23:31 -0400 Subject: [PATCH 17/26] More debug code cleanup --- src/commodity.cc | 50 ++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/commodity.cc b/src/commodity.cc index 61fd0fe5..c2fc0935 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -140,26 +140,26 @@ commodity_t::history_t::find_price(const optional& 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) { DEBUG_INDENT("commodity.prices.find", indent); - DEBUG("commodity.prices.find", " there are no prices in this history"); + 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; DEBUG_INDENT("commodity.prices.find", indent); - DEBUG("commodity.prices.find", " using most recent price"); + 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; @@ -167,7 +167,7 @@ commodity_t::history_t::find_price(const optional& moment, found = true; DEBUG_INDENT("commodity.prices.find", indent); - DEBUG("commodity.prices.find", " using last price"); + DEBUG("commodity.prices.find", "using last price"); } else { point.when = (*i).first; if (*moment < point.when) { @@ -183,29 +183,29 @@ commodity_t::history_t::find_price(const optional& moment, } DEBUG_INDENT("commodity.prices.find", indent); - DEBUG("commodity.prices.find", " using found price"); + DEBUG("commodity.prices.find", "using found price"); } } if (! found) { DEBUG_INDENT("commodity.prices.find", indent); - DEBUG("commodity.prices.find", " could not find a price"); + DEBUG("commodity.prices.find", "could not find a price"); return none; } else if (moment && point.when > *moment) { DEBUG_INDENT("commodity.prices.find", indent); - DEBUG("commodity.prices.find", " price is too young "); + DEBUG("commodity.prices.find", "price is too young "); return none; } else if (oldest && point.when < *oldest) { DEBUG_INDENT("commodity.prices.find", indent); - DEBUG("commodity.prices.find", " price is too old "); + DEBUG("commodity.prices.find", "price is too old "); return none; } else { DEBUG_INDENT("commodity.prices.find", indent); DEBUG("commodity.prices.find", - " returning price: " << point.when << ", " << point.price); + "returning price: " << point.when << ", " << point.price); return point; } } @@ -235,19 +235,19 @@ commodity_t::varied_history_t::find_price(const commodity_t& source, DEBUG_INDENT("commodity.prices.find", indent); DEBUG("commodity.prices.find", "varied_find_price for: " << source); - DEBUG_INDENT("commodity.prices.find", indent + 1); + DEBUG_INDENT("commodity.prices.find", indent); if (commodity) DEBUG("commodity.prices.find", "looking for: commodity '" << *commodity << "'"); else DEBUG("commodity.prices.find", "looking for: any commodity"); if (moment) { - DEBUG_INDENT("commodity.prices.find", indent + 1); + DEBUG_INDENT("commodity.prices.find", indent); DEBUG("commodity.prices.find", "time index: " << *moment); } if (oldest) { - DEBUG_INDENT("commodity.prices.find", indent + 1); + DEBUG_INDENT("commodity.prices.find", indent); DEBUG("commodity.prices.find", "only consider prices younger than: " << *oldest); } #endif @@ -268,13 +268,13 @@ commodity_t::varied_history_t::find_price(const commodity_t& source, if (! commodity && ! comm.has_flags(COMMODITY_PRIMARY)) continue; - DEBUG_INDENT("commodity.prices.find", indent + 1); + DEBUG_INDENT("commodity.prices.find", indent); DEBUG("commodity.prices.find", "searching for price via commodity '" << comm << "'"); point = hist.second.find_price(moment, limit #if defined(DEBUG_ON) - , indent + 2 + , indent + 1 #endif ); assert(! point || point->price.commodity() == comm); @@ -283,16 +283,16 @@ commodity_t::varied_history_t::find_price(const commodity_t& source, optional xlat; if (commodity && comm != *commodity) { - DEBUG_INDENT("commodity.prices.find", indent + 1); + DEBUG_INDENT("commodity.prices.find", indent); DEBUG("commodity.prices.find", "looking for translation price"); xlat = comm.find_price(commodity, moment, limit #if defined(DEBUG_ON) - , indent + 2 + , indent + 1 #endif ); if (xlat) { - DEBUG_INDENT("commodity.prices.find", indent + 1); + DEBUG_INDENT("commodity.prices.find", indent); DEBUG("commodity.prices.find", "found translated price " << xlat->price << " from " << xlat->when); @@ -300,12 +300,12 @@ commodity_t::varied_history_t::find_price(const commodity_t& source, if (xlat->when < point->when) { point->when = xlat->when; - DEBUG_INDENT("commodity.prices.find", indent + 1); + DEBUG_INDENT("commodity.prices.find", indent); DEBUG("commodity.prices.find", "adjusting date of result back to " << point->when); } } else { - DEBUG_INDENT("commodity.prices.find", indent + 1); + DEBUG_INDENT("commodity.prices.find", indent); DEBUG("commodity.prices.find", "saw no translated price there"); continue; } @@ -313,7 +313,7 @@ commodity_t::varied_history_t::find_price(const commodity_t& source, assert(! commodity || point->price.commodity() == *commodity); - DEBUG_INDENT("commodity.prices.find", indent + 1); + DEBUG_INDENT("commodity.prices.find", indent); DEBUG("commodity.prices.find", "saw a price there: " << point->price << " from " << point->when); @@ -322,18 +322,18 @@ commodity_t::varied_history_t::find_price(const commodity_t& source, best = *point; found = true; - DEBUG_INDENT("commodity.prices.find", indent + 1); + DEBUG_INDENT("commodity.prices.find", indent); DEBUG("commodity.prices.find", "search limit adjusted to " << *limit); } } else { - DEBUG_INDENT("commodity.prices.find", indent + 1); + DEBUG_INDENT("commodity.prices.find", indent); DEBUG("commodity.prices.find", "saw no price there"); } } if (found) { - DEBUG_INDENT("commodity.prices.find", indent + 1); + DEBUG_INDENT("commodity.prices.find", indent); DEBUG("commodity.download", "found price " << best.price << " from " << best.when); return best; From a4a45cb4d61e028a19be3fb5be889e62dc83214e Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Fri, 4 Jun 2010 03:40:39 -0400 Subject: [PATCH 18/26] any and all do not need to be reserved tokens --- src/commodity.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/commodity.cc b/src/commodity.cc index c2fc0935..2ed6553b 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -418,9 +418,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': From f16a5382ed9a9750c69595e5752f80e39cf7a4b8 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Thu, 3 Jun 2010 05:56:30 -0400 Subject: [PATCH 19/26] commodity_t::find_price now uses memoization This reduces the slowdown of using -V and -X from 36x in some cases down to around 4-5x (for a debug build). --- src/commodity.cc | 111 ++++++++++++++++++++++++++++++++++++++++++----- src/commodity.h | 41 +++++++++-------- 2 files changed, 123 insertions(+), 29 deletions(-) diff --git a/src/commodity.cc b/src/commodity.cc index 2ed6553b..1554887c 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -268,13 +268,13 @@ commodity_t::varied_history_t::find_price(const commodity_t& source, if (! commodity && ! comm.has_flags(COMMODITY_PRIMARY)) continue; - DEBUG_INDENT("commodity.prices.find", indent); + DEBUG_INDENT("commodity.prices.find", indent + 1); DEBUG("commodity.prices.find", "searching for price via commodity '" << comm << "'"); point = hist.second.find_price(moment, limit #if defined(DEBUG_ON) - , indent + 1 + , indent + 2 #endif ); assert(! point || point->price.commodity() == comm); @@ -283,16 +283,16 @@ commodity_t::varied_history_t::find_price(const commodity_t& source, optional xlat; if (commodity && comm != *commodity) { - DEBUG_INDENT("commodity.prices.find", indent); + DEBUG_INDENT("commodity.prices.find", indent + 1); 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 + 1 + , indent + 2 #endif ); if (xlat) { - DEBUG_INDENT("commodity.prices.find", indent); + DEBUG_INDENT("commodity.prices.find", indent + 1); DEBUG("commodity.prices.find", "found translated price " << xlat->price << " from " << xlat->when); @@ -300,12 +300,12 @@ commodity_t::varied_history_t::find_price(const commodity_t& source, if (xlat->when < point->when) { point->when = xlat->when; - DEBUG_INDENT("commodity.prices.find", indent); + DEBUG_INDENT("commodity.prices.find", indent + 1); DEBUG("commodity.prices.find", "adjusting date of result back to " << point->when); } } else { - DEBUG_INDENT("commodity.prices.find", indent); + DEBUG_INDENT("commodity.prices.find", indent + 1); DEBUG("commodity.prices.find", "saw no translated price there"); continue; } @@ -313,7 +313,7 @@ commodity_t::varied_history_t::find_price(const commodity_t& source, assert(! commodity || point->price.commodity() == *commodity); - DEBUG_INDENT("commodity.prices.find", indent); + DEBUG_INDENT("commodity.prices.find", indent + 1); DEBUG("commodity.prices.find", "saw a price there: " << point->price << " from " << point->when); @@ -322,12 +322,12 @@ commodity_t::varied_history_t::find_price(const commodity_t& source, best = *point; found = true; - DEBUG_INDENT("commodity.prices.find", indent); + DEBUG_INDENT("commodity.prices.find", indent + 1); DEBUG("commodity.prices.find", "search limit adjusted to " << *limit); } } else { - DEBUG_INDENT("commodity.prices.find", indent); + DEBUG_INDENT("commodity.prices.find", indent + 1); DEBUG("commodity.prices.find", "saw no price there"); } } @@ -360,6 +360,95 @@ commodity_t::varied_history_t::history(const optional& commodity) return none; } +optional +commodity_t::find_price(const optional& commodity, + const optional& moment, + const optional& 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 pair; +#if defined(VERIFY_ON) + optional checkpoint; +#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() { + checkpoint = (*i).second; + } else +#endif // defined(VERIFY_ON) + return (*i).second; + } + } + + optional point; + + const_cast(*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(*this).drop_flags(COMMODITY_WALKED); + throw; + } + const_cast(*this).drop_flags(COMMODITY_WALKED); + +#if defined(VERIFY_ON) + if (DO_VERIFY() && pair) { + 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 commodity_t::check_for_updated_price(const optional& point, const optional& moment, diff --git a/src/commodity.h b/src/commodity.h index 483d98b0..d8aad10d 100644 --- a/src/commodity.h +++ b/src/commodity.h @@ -59,6 +59,10 @@ struct price_point_t datetime_t when; amount_t price; + bool operator==(const price_point_t& other) const { + return when == other.when && price == other.price; + } + #if defined(HAVE_BOOST_SERIALIZATION) private: /** Serialization. */ @@ -175,6 +179,16 @@ protected: optional smaller; optional larger; + typedef std::pair, + optional > optional_time_pair_t; + typedef std::pair time_and_commodity_t; + typedef std::map > memoized_price_map; + + static const std::size_t max_price_map_size = 16; + mutable memoized_price_map price_map; + mutable bool searched; public: @@ -334,37 +348,28 @@ public: const bool reflexive = true) { if (! base->varied_history) base->varied_history = varied_history_t(); - base->varied_history->add_price(*this, date, price, reflexive); + DEBUG("commodity.prices.find", "Price added, clearing price_map"); + base->price_map.clear(); // a price was added, invalid the map } bool remove_price(const datetime_t& date, commodity_t& commodity) { - if (base->varied_history) + if (base->varied_history) { base->varied_history->remove_price(date, commodity); + DEBUG("commodity.prices.find", "Price removed, clearing price_map"); + base->price_map.clear(); // a price was added, invalid the map + } return false; } optional find_price(const optional& commodity = none, const optional& moment = none, - const optional& oldest = none + const optional& oldest = none, + const bool nested = false #if defined(DEBUG_ON) , const int indent = 0 #endif - ) const { - if (! has_flags(COMMODITY_WALKED) && base->varied_history && - (commodity || ! has_flags(COMMODITY_PRIMARY))) { - const_cast(*this).add_flags(COMMODITY_WALKED); - optional point = - base->varied_history->find_price(*this, commodity, moment, oldest -#if defined(DEBUG_ON) - , indent -#endif - ); - const_cast(*this).drop_flags(COMMODITY_WALKED); - return point; - } - return none; - } + ) const; optional check_for_updated_price(const optional& point, From b848ace76866188701a6a704a9531c4eeb2bc71a Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Fri, 4 Jun 2010 06:02:00 -0400 Subject: [PATCH 20/26] Allow opt -NDEBUG build to complete without warnings --- src/amount.cc | 4 ++++ src/exprbase.h | 4 ++++ src/filters.cc | 2 ++ src/global.cc | 2 ++ src/op.cc | 2 ++ src/parser.h | 6 ++++++ src/py_utils.cc | 2 ++ src/textual.cc | 10 ++++++++++ src/times.cc | 2 ++ src/utils.h | 8 ++++---- src/xact.cc | 2 ++ 11 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/amount.cc b/src/amount.cc index 2837178c..7eb94442 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -240,14 +240,18 @@ void amount_t::initialize() // in terms of seconds, but reported as minutes or hours. if (commodity_t * commodity = commodity_pool_t::current_pool->create("s")) commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET); +#if !defined(NO_ASSERTS) else assert(false); +#endif // Add a "percentile" commodity if (commodity_t * commodity = commodity_pool_t::current_pool->create("%")) commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET); +#if !defined(NO_ASSERTS) else assert(false); +#endif is_initialized = true; } diff --git a/src/exprbase.h b/src/exprbase.h index 0dbf3bff..cf81a0a7 100644 --- a/src/exprbase.h +++ b/src/exprbase.h @@ -155,17 +155,21 @@ public: result_type calc(scope_t& scope) { if (! compiled) { +#if defined(DEBUG_ON) if (SHOW_DEBUG("expr.compile")) { DEBUG("expr.compile", "Before compilation:"); dump(*_log_stream); } +#endif // defined(DEBUG_ON) compile(scope); +#if defined(DEBUG_ON) if (SHOW_DEBUG("expr.compile")) { DEBUG("expr.compile", "After compilation:"); dump(*_log_stream); } +#endif // defined(DEBUG_ON) } return real_calc(scope); diff --git a/src/filters.cc b/src/filters.cc index 70a46e8e..b5f9983a 100644 --- a/src/filters.cc +++ b/src/filters.cc @@ -1166,8 +1166,10 @@ void forecast_posts::flush() } date_t& begin = *(*least).first.start; +#if !defined(NO_ASSERTS) if ((*least).first.finish) assert(begin < *(*least).first.finish); +#endif // If the next date in the series for this periodic posting is more than 5 // years beyond the last valid post we generated, drop it from further diff --git a/src/global.cc b/src/global.cc index 170509b0..35651ddb 100644 --- a/src/global.cc +++ b/src/global.cc @@ -391,11 +391,13 @@ global_scope_t::read_command_arguments(scope_t& scope, strings_list args) void global_scope_t::normalize_session_options() { +#if defined(LOGGING_ON) INFO("Initialization file is " << HANDLER(init_file_).str()); INFO("Price database is " << session().HANDLER(price_db_).str()); foreach (const path& pathname, session().HANDLER(file_).data_files) INFO("Journal file is " << pathname.string()); +#endif // defined(LOGGING_ON) } expr_t::func_t global_scope_t::look_for_precommand(scope_t& scope, diff --git a/src/op.cc b/src/op.cc index df222802..ca720535 100644 --- a/src/op.cc +++ b/src/op.cc @@ -78,10 +78,12 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope, const int depth) // Identifier references are first looked up at the point of // definition, and then at the point of every use if they could // not be found there. +#if defined(DEBUG_ON) if (SHOW_DEBUG("expr.compile")) { DEBUG("expr.compile", "Found definition:"); def->dump(*_log_stream, 0); } +#endif // defined(DEBUG_ON) return copy(def); } else if (left()) { diff --git a/src/parser.h b/src/parser.h index aab48830..2693fc79 100644 --- a/src/parser.h +++ b/src/parser.h @@ -61,10 +61,16 @@ class expr_t::parser_t : public noncopyable return lookahead; } +#if !defined(NO_ASSERTS) void push_token(const token_t& tok) const { assert(&tok == &lookahead); use_lookahead = true; } +#else + void push_token(const token_t&) const { + use_lookahead = true; + } +#endif // !defined(NO_ASSERTS) void push_token() const { use_lookahead = true; } diff --git a/src/py_utils.cc b/src/py_utils.cc index 4b364e5d..952416cc 100644 --- a/src/py_utils.cc +++ b/src/py_utils.cc @@ -115,8 +115,10 @@ struct string_from_python utf8::unchecked::utf16to8(value, value + size, std::back_inserter(str)); else if (sizeof(Py_UNICODE) == 4) // UTF-32 utf8::unchecked::utf32to8(value, value + size, std::back_inserter(str)); +#if !defined(NO_ASSERTS) else assert(! "Py_UNICODE has an unexpected size"); +#endif if (value == 0) throw_error_already_set(); void* storage = diff --git a/src/textual.cc b/src/textual.cc index 9a49edd4..85b1a14b 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -695,8 +695,10 @@ void instance_t::master_account_directive(char * line) { if (account_t * acct = context.top_account()->find_account(line)) context.state_stack.push_front(acct); +#if !defined(NO_ASSERTS) else assert(! "Failed to create account"); +#endif } void instance_t::end_directive(char * kind) @@ -763,8 +765,12 @@ void instance_t::payee_mapping_directive(char * line) (payee_mapping_t(mask_t(regex), payee)); while (peek_whitespace_line()) { +#if defined(NO_ASSERTS) + read_line(line); +#else std::streamsize len = read_line(line); assert(len > 0); +#endif regex = skip_ws(line); if (! *regex) @@ -786,8 +792,12 @@ void instance_t::account_mapping_directive(char * line) context.top_account()->find_account(account_name))); while (peek_whitespace_line()) { +#if defined(NO_ASSERTS) + read_line(line); +#else std::streamsize len = read_line(line); assert(len > 0); +#endif payee_regex = skip_ws(line); if (! *payee_regex) diff --git a/src/times.cc b/src/times.cc index a7906aee..60e8e7cc 100644 --- a/src/times.cc +++ b/src/times.cc @@ -333,10 +333,12 @@ date_t date_specifier_t::begin(const optional_year& current_year) const month_type the_month = month ? *month : date_t::month_type(1); day_type the_day = day ? *day : date_t::day_type(1); +#if !defined(NO_ASSERTS) if (day) assert(! wday); else if (wday) assert(! day); +#endif // jww (2009-11-16): Handle wday. If a month is set, find the most recent // wday in that month; if the year is set, then in that year. diff --git a/src/utils.h b/src/utils.h index a0c3f49f..24f424b7 100644 --- a/src/utils.h +++ b/src/utils.h @@ -434,8 +434,8 @@ void finish_timer(const char * name); (SHOW_TRACE(lvl) ? ledger::finish_timer(#name) : ((void)0)) #else #define TRACE_START(name, lvl, msg) -#define TRACE_STOP(name) -#define TRACE_FINISH(name) +#define TRACE_STOP(name, lvl) +#define TRACE_FINISH(name, lvl) #endif #if defined(DEBUG_ON) @@ -474,8 +474,8 @@ void finish_timer(const char * name); #else // ! (LOGGING_ON && TIMERS_ON) #define TRACE_START(lvl, msg, name) -#define TRACE_STOP(name) -#define TRACE_FINISH(name) +#define TRACE_STOP(name, lvl) +#define TRACE_FINISH(name, lvl) #define DEBUG_START(name, msg) #define DEBUG_START_(name, cat, msg) diff --git a/src/xact.cc b/src/xact.cc index 569e5869..6c10ac04 100644 --- a/src/xact.cc +++ b/src/xact.cc @@ -62,10 +62,12 @@ xact_base_t::~xact_base_t() void xact_base_t::add_post(post_t * post) { +#if !defined(NO_ASSERTS) // You can add temporary postings to transactions, but not real postings to // temporary transactions. if (! post->has_flags(ITEM_TEMP)) assert(! has_flags(ITEM_TEMP)); +#endif posts.push_back(post); } From 83c115d78afec45e1815bae7ec30b8e92309e679 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Fri, 4 Jun 2010 16:28:57 -0400 Subject: [PATCH 21/26] Look for Boost in lib64, as well as lib --- acprep | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/acprep b/acprep index 87e2cd64..f48649eb 100755 --- a/acprep +++ b/acprep @@ -124,7 +124,9 @@ class BoostInfo(object): return None def locate_boost(self): - for path in map(lambda x: join(x, 'lib'), search_prefixes): + lib64_dirs = map(lambda x: join(x, 'lib64'), search_prefixes) + lib_dirs = map(lambda x: join(x, 'lib'), search_prefixes) + for path in lib64_dirs + lib_dirs: self.log.info('Looking for Boost in %s...' % path) self.suffix = self.find_boost_in_directory(path) if self.suffix is not None: From 653d2bd99a04f422c3755f42d6091f2b8817b26f Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sat, 5 Jun 2010 01:57:16 -0400 Subject: [PATCH 22/26] Corrected a verification test --- src/commodity.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/commodity.cc b/src/commodity.cc index 1554887c..e45332b2 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -375,6 +375,7 @@ commodity_t::find_price(const optional& commodity, optional pair; #if defined(VERIFY_ON) optional checkpoint; + bool found = false; #endif if (! nested) { @@ -394,6 +395,7 @@ commodity_t::find_price(const optional& commodity, << ((*i).second ? (*i).second->price : amount_t(0L))); #if defined(VERIFY_ON) IF_VERIFY() { + found = true; checkpoint = (*i).second; } else #endif // defined(VERIFY_ON) @@ -422,7 +424,7 @@ commodity_t::find_price(const optional& commodity, const_cast(*this).drop_flags(COMMODITY_WALKED); #if defined(VERIFY_ON) - if (DO_VERIFY() && pair) { + if (DO_VERIFY() && found) { VERIFY(checkpoint == point); return checkpoint; } From 63c7ba0322fc3d0082580e181cd341f32a23ee9e Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sat, 5 Jun 2010 02:44:46 -0400 Subject: [PATCH 23/26] Make --anon work with the print command Fixes #226 / C1C1E731-D991-40ED-BE43-8ED55585386C --- src/filters.cc | 1 + src/post.h | 11 ++++++----- src/print.cc | 1 + 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/filters.cc b/src/filters.cc index b5f9983a..07278500 100644 --- a/src/filters.cc +++ b/src/filters.cc @@ -256,6 +256,7 @@ void anonymize_posts::operator()(post_t& post) create_temp_account_from_path(account_names, temps, xact.journal->master); post_t& temp = temps.copy_post(post, xact, new_account); temp.note = none; + temp.add_flags(POST_ANONYMIZED); (*handler)(temp); } diff --git a/src/post.h b/src/post.h index 226d6289..ed22634f 100644 --- a/src/post.h +++ b/src/post.h @@ -52,11 +52,12 @@ class account_t; class post_t : public item_t { public: -#define POST_VIRTUAL 0x08 // the account was specified with (parens) -#define POST_MUST_BALANCE 0x10 // posting must balance in the transaction -#define POST_CALCULATED 0x20 // posting's amount was calculated -#define POST_COST_CALCULATED 0x40 // posting's cost was calculated -#define POST_COST_IN_FULL 0x80 // cost specified using @@ +#define POST_VIRTUAL 0x04 // the account was specified with (parens) +#define POST_MUST_BALANCE 0x08 // posting must balance in the transaction +#define POST_CALCULATED 0x10 // posting's amount was calculated +#define POST_COST_CALCULATED 0x20 // posting's cost was calculated +#define POST_COST_IN_FULL 0x40 // cost specified using @@ +#define POST_ANONYMIZED 0x80 // a temporary, anonymous posting xact_t * xact; // only set for posts of regular xacts account_t * account; diff --git a/src/print.cc b/src/print.cc index f93f5fe8..703e885c 100644 --- a/src/print.cc +++ b/src/print.cc @@ -120,6 +120,7 @@ namespace { foreach (post_t * post, xact.posts) { if (post->has_flags(ITEM_TEMP | ITEM_GENERATED) && + ! post->has_flags(POST_ANONYMIZED) && ! report.HANDLED(print_virtual)) continue; From 16f799767ce86731f67735e9a59bde5faa4cf645 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sat, 5 Jun 2010 03:22:02 -0400 Subject: [PATCH 24/26] Value expression sequences are now comparable Fixes #228 / ED9388D7-E523-40EB-841B-9AE9BAA70329 --- src/filters.h | 12 ++++-------- src/value.cc | 28 ++++++++++++++++++++++++++++ src/value.h | 2 -- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/filters.h b/src/filters.h index a66d8c47..327499fb 100644 --- a/src/filters.h +++ b/src/filters.h @@ -226,16 +226,12 @@ class sort_posts : public item_handler public: sort_posts(post_handler_ptr handler, const expr_t& _sort_order) - : item_handler(handler), - sort_order(_sort_order) { - TRACE_CTOR(sort_posts, - "post_handler_ptr, const value_expr&"); + : item_handler(handler), sort_order(_sort_order) { + TRACE_CTOR(sort_posts, "post_handler_ptr, const value_expr&"); } sort_posts(post_handler_ptr handler, const string& _sort_order) - : item_handler(handler), - sort_order(_sort_order) { - TRACE_CTOR(sort_posts, - "post_handler_ptr, const string&"); + : item_handler(handler), sort_order(_sort_order) { + TRACE_CTOR(sort_posts, "post_handler_ptr, const string&"); } virtual ~sort_posts() { TRACE_DTOR(sort_posts); diff --git a/src/value.cc b/src/value.cc index a967eeb8..e9313f0c 100644 --- a/src/value.cc +++ b/src/value.cc @@ -935,6 +935,20 @@ bool value_t::is_less_than(const value_t& val) const } return ! no_amounts; } + case SEQUENCE: { + sequence_t::const_iterator i = as_sequence().begin(); + sequence_t::const_iterator j = val.as_sequence().begin(); + for (; (i != as_sequence().end() && + j != val.as_sequence().end()); i++, j++) { + if (! ((*i) < (*j))) + return false; + } + if (i == as_sequence().end()) + return true; + else + return false; + break; + } default: break; } @@ -1041,6 +1055,20 @@ bool value_t::is_greater_than(const value_t& val) const } return ! no_amounts; } + case SEQUENCE: { + sequence_t::const_iterator i = as_sequence().begin(); + sequence_t::const_iterator j = val.as_sequence().begin(); + for (; (i != as_sequence().end() && + j != val.as_sequence().end()); i++, j++) { + if (! ((*i) > (*j))) + return false; + } + if (i == as_sequence().end()) + return false; + else + return true; + break; + } default: break; } diff --git a/src/value.h b/src/value.h index 3252ed65..2e3998f3 100644 --- a/src/value.h +++ b/src/value.h @@ -878,7 +878,6 @@ public: sequence_t::iterator begin() { return as_sequence_lval().begin(); } - sequence_t::iterator end() { return as_sequence_lval().end(); } @@ -886,7 +885,6 @@ public: sequence_t::const_iterator begin() const { return as_sequence().begin(); } - sequence_t::const_iterator end() const { return as_sequence().end(); } From 2c65b95e49a1cec1c4f2fa6bcd2d31629f358f92 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sat, 5 Jun 2010 04:28:33 -0400 Subject: [PATCH 25/26] Made "expr" command a synonym for "parse" --- src/report.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/report.cc b/src/report.cc index e51736fd..f0923b33 100644 --- a/src/report.cc +++ b/src/report.cc @@ -1473,6 +1473,8 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, case 'e': if (is_eq(p, "eval")) return WRAP_FUNCTOR(eval_command); + else if (is_eq(p, "expr")) + return WRAP_FUNCTOR(parse_command); break; case 'f': if (is_eq(p, "format")) From 1417b40fdf0a92a85ab01f233c0ae076079901a2 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sat, 5 Jun 2010 04:49:10 -0400 Subject: [PATCH 26/26] Enabled timers and logging in NDEBUG builds --- src/utils.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils.h b/src/utils.h index 24f424b7..9135abde 100644 --- a/src/utils.h +++ b/src/utils.h @@ -49,17 +49,17 @@ */ /*@{*/ +#define TIMERS_ON 1 + #if defined(DEBUG_MODE) #define VERIFY_ON 1 #define TRACING_ON 1 #define DEBUG_ON 1 -#define TIMERS_ON 1 #elif defined(NDEBUG) #define NO_ASSERTS 1 -#define NO_LOGGING 1 +//#define NO_LOGGING 1 #else #define TRACING_ON 1 // use --trace X to enable -#define TIMERS_ON 1 #endif /*@}*/