summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2009-03-06 04:05:00 -0400
committerJohn Wiegley <johnw@newartisans.com>2009-03-06 04:07:25 -0400
commitf340d50362340c330de83d419eb41c0ede162c49 (patch)
tree9a30d7bd034c3fa37092725d419f896108536633 /src
parent4a0f5f9034dc24c7ae5f0464d407f4cf2279558b (diff)
downloadfork-ledger-f340d50362340c330de83d419eb41c0ede162c49.tar.gz
fork-ledger-f340d50362340c330de83d419eb41c0ede162c49.tar.bz2
fork-ledger-f340d50362340c330de83d419eb41c0ede162c49.zip
Revised the ways statistics are computed
It is no longer done in calc_posts, but recursively on each account. This allows value expressions to ask statistical questions, like "earliest cleared posting?" (TBD) from any specific account, computed lazily.
Diffstat (limited to 'src')
-rw-r--r--src/account.cc43
-rw-r--r--src/account.h49
-rw-r--r--src/output.cc98
-rw-r--r--src/output.h46
-rw-r--r--src/report.cc6
-rw-r--r--src/stats.cc125
-rw-r--r--src/stats.h59
7 files changed, 237 insertions, 189 deletions
diff --git a/src/account.cc b/src/account.cc
index b9955120..0db42cdb 100644
--- a/src/account.cc
+++ b/src/account.cc
@@ -309,7 +309,36 @@ std::size_t account_t::children_with_flags(xdata_t::flags_t flags) const
account_t::xdata_t::details_t&
account_t::xdata_t::details_t::operator+=(const details_t& other)
{
- // jww (2009-03-05): NYI
+ posts_count += other.posts_count;
+ posts_virtuals_count += other.posts_virtuals_count;
+ posts_cleared_count += other.posts_cleared_count;
+ posts_last_7_count += other.posts_last_7_count;
+ posts_last_30_count += other.posts_last_30_count;
+ posts_this_month_count += other.posts_this_month_count;
+
+ if (! is_valid(earliest_post) ||
+ (is_valid(other.earliest_post) &&
+ other.earliest_post < earliest_post))
+ earliest_post = other.earliest_post;
+ if (! is_valid(earliest_cleared_post) ||
+ (is_valid(other.earliest_cleared_post) &&
+ other.earliest_cleared_post < earliest_cleared_post))
+ earliest_cleared_post = other.earliest_cleared_post;
+
+ if (! is_valid(latest_post) ||
+ (is_valid(other.latest_post) &&
+ other.latest_post > latest_post))
+ latest_post = other.latest_post;
+ if (! is_valid(latest_cleared_post) ||
+ (is_valid(other.latest_cleared_post) &&
+ other.latest_cleared_post > latest_cleared_post))
+ latest_cleared_post = other.latest_cleared_post;
+
+ filenames.insert(other.filenames.begin(), other.filenames.end());
+ accounts_referenced.insert(other.accounts_referenced.begin(),
+ other.accounts_referenced.end());
+ payees_referenced.insert(other.payees_referenced.begin(),
+ other.payees_referenced.end());
return *this;
}
@@ -377,7 +406,7 @@ account_t::family_details(bool gather_all) const
foreach (const accounts_map::value_type& pair, accounts)
xdata_->family_details += pair.second->family_details(gather_all);
- xdata_->self_details += self_details(gather_all);
+ xdata_->family_details += self_details(gather_all);
}
return xdata_->family_details;
}
@@ -385,16 +414,8 @@ account_t::family_details(bool gather_all) const
void account_t::xdata_t::details_t::update(post_t& post,
bool gather_all)
{
- if (last_xact != post.xact) {
- xacts_count++;
- last_xact = post.xact;
- }
- if (last_post == &post)
- return;
-
- last_post = &post;
-
posts_count++;
+
if (post.has_flags(POST_VIRTUAL))
posts_virtuals_count++;
diff --git a/src/account.h b/src/account.h
index f161a11f..0fa03dde 100644
--- a/src/account.h
+++ b/src/account.h
@@ -138,41 +138,34 @@ class account_t : public scope_t
struct details_t
{
- value_t total;
- bool calculated;
- bool gathered;
+ value_t total;
+ bool calculated;
+ bool gathered;
// The following are only calculated if --totals is enabled
- std::size_t xacts_count;
+ std::size_t posts_count;
+ std::size_t posts_virtuals_count;
+ std::size_t posts_cleared_count;
+ std::size_t posts_last_7_count;
+ std::size_t posts_last_30_count;
+ std::size_t posts_this_month_count;
- std::size_t posts_count;
- std::size_t posts_virtuals_count;
- std::size_t posts_cleared_count;
- std::size_t posts_last_7_count;
- std::size_t posts_last_30_count;
- std::size_t posts_this_month_count;
+ date_t earliest_post;
+ date_t earliest_cleared_post;
+ date_t latest_post;
+ date_t latest_cleared_post;
- date_t earliest_post;
- date_t earliest_cleared_post;
- date_t latest_post;
- date_t latest_cleared_post;
-
- xact_t * last_xact;
- post_t * last_post;
-
- std::size_t last_size;
+ std::size_t last_size;
// The following are only calculated if --gather is enabled
- std::set<path> filenames;
- std::set<string> accounts_referenced;
- std::set<string> payees_referenced;
+ std::set<path> filenames;
+ std::set<string> accounts_referenced;
+ std::set<string> payees_referenced;
details_t()
: calculated(false),
gathered(false),
- xacts_count(0),
-
posts_count(0),
posts_virtuals_count(0),
posts_cleared_count(0),
@@ -180,14 +173,6 @@ class account_t : public scope_t
posts_last_30_count(0),
posts_this_month_count(0),
- earliest_post(0),
- earliest_cleared_post(0),
- latest_post(0),
- latest_cleared_post(0),
-
- last_xact(NULL),
- last_post(NULL),
-
last_size(0) {}
details_t& operator+=(const details_t& other);
diff --git a/src/output.cc b/src/output.cc
index 975d8077..02bd7120 100644
--- a/src/output.cc
+++ b/src/output.cc
@@ -111,104 +111,6 @@ void format_posts::operator()(post_t& post)
}
}
-void gather_statistics::flush()
-{
- std::ostream& out(report.output_stream);
-
- {
- straccstream accum;
- out << ACCUM(accum << "Time period: %1 to %2" << statistics.earliest_post
- << statistics.latest_post) << std::endl << std::endl;
- }
-
- out << _(" Files these postings came from:") << std::endl;
-
- foreach (const path& pathname, statistics.filenames)
- if (! pathname.empty())
- out << " " << pathname.string() << std::endl;
- out << std::endl;
-
- out << _(" Unique payees: ");
- out.width(8);
- out << std::right << statistics.payees_referenced.size() << std::endl;
-
- out << _(" Unique accounts: ");
- out.width(8);
- out << std::right << statistics.accounts_referenced.size() << std::endl;
-
- out << _(" Number of transactions: ") ;
- out.width(8);
- out << std::right << statistics.total_xacts << std::endl;
-
- out << _(" Number of postings: ");
- out.width(8);
- out << std::right << statistics.total_posts;
-
- out << " (";
- out.precision(2);
- out << (double((statistics.latest_post - statistics.earliest_post).days()) /
- double(statistics.total_posts)) << _(" per day)") << std::endl;
-
- out << _(" Days since last post: ");
- out.width(8);
- out << std::right << (CURRENT_DATE() - statistics.latest_post).days()
- << std::endl;
-
- out << _(" Posts in last 7 days: ");
- out.width(8);
- out << std::right << statistics.total_last_7_days << std::endl;
- out << _(" Posts in last 30 days: ");
- out.width(8);
- out << std::right << statistics.total_last_30_days << std::endl;
- out << _(" Posts seen this month: ");
- out.width(8);
- out << std::right << statistics.total_this_month << std::endl;
-
- out << _(" Uncleared postings: ");
- out.width(8);
- out << std::right << statistics.total_uncleared_posts << std::endl;
-
- out.flush();
-}
-
-void gather_statistics::operator()(post_t& post)
-{
- if (last_xact != post.xact) {
- statistics.total_xacts++;
- last_xact = post.xact;
- }
- if (last_post != &post) {
- statistics.total_posts++;
- last_post = &post;
-
- statistics.filenames.insert(post.pathname);
-
- date_t date = post.date();
-
- if (date.year() == CURRENT_DATE().year() &&
- date.month() == CURRENT_DATE().month())
- statistics.total_this_month++;
-
- if ((CURRENT_DATE() - date).days() <= 30)
- statistics.total_last_30_days++;
- if ((CURRENT_DATE() - date).days() <= 7)
- statistics.total_last_7_days++;
-
- if (post.state() != item_t::CLEARED)
- statistics.total_uncleared_posts++;
-
- if (! is_valid(statistics.earliest_post) ||
- post.date() < statistics.earliest_post)
- statistics.earliest_post = post.date();
- if (! is_valid(statistics.latest_post) ||
- post.date() > statistics.latest_post)
- statistics.latest_post = post.date();
-
- statistics.accounts_referenced.insert(post.account->fullname());
- statistics.payees_referenced.insert(post.xact->payee);
- }
-}
-
format_accounts::format_accounts(report_t& _report,
const string& format)
: report(_report), disp_pred()
diff --git a/src/output.h b/src/output.h
index c7e108fe..19dc5e20 100644
--- a/src/output.h
+++ b/src/output.h
@@ -89,52 +89,6 @@ public:
*
* Long.
*/
-class gather_statistics : public item_handler<post_t>
-{
-protected:
- report_t& report;
- xact_t * last_xact;
- post_t * last_post;
-
- struct statistics_t {
- std::set<path> filenames;
-
- std::size_t total_xacts;
- std::size_t total_posts;
- std::size_t total_uncleared_posts;
- std::size_t total_last_7_days;
- std::size_t total_last_30_days;
- std::size_t total_this_month;
-
- date_t earliest_post;
- date_t latest_post;
-
- std::set<string> accounts_referenced;
- std::set<string> payees_referenced;
-
- statistics_t()
- : total_xacts(0), total_posts(0), total_uncleared_posts(0),
- total_last_7_days(0), total_last_30_days(0), total_this_month(0) {}
- } statistics;
-
-public:
- gather_statistics(report_t& _report)
- : report(_report), last_xact(NULL), last_post(NULL) {
- TRACE_CTOR(gather_statistics, "report&");
- }
- virtual ~gather_statistics() {
- TRACE_DTOR(gather_statistics);
- }
-
- virtual void flush();
- virtual void operator()(post_t& post);
-};
-
-/**
- * @brief Brief
- *
- * Long.
- */
class format_accounts : public item_handler<account_t>
{
protected:
diff --git a/src/report.cc b/src/report.cc
index e4eef741..76546528 100644
--- a/src/report.cc
+++ b/src/report.cc
@@ -37,6 +37,7 @@
#include "iterators.h"
#include "filters.h"
#include "precmd.h"
+#include "stats.h"
#include "generate.h"
#include "derive.h"
#include "emacs.h"
@@ -728,8 +729,9 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
case 's':
if (is_eq(q, "stats") || is_eq(q, "stat"))
- return WRAP_FUNCTOR(reporter<>(new gather_statistics(*this), *this));
- else if (is_eq(q, "server") && maybe_import("ledger.server"))
+ return WRAP_FUNCTOR(report_statistics);
+ else
+ if (is_eq(q, "server") && maybe_import("ledger.server"))
return session.lookup(string(CMD_PREFIX) + "server");
break;
}
diff --git a/src/stats.cc b/src/stats.cc
new file mode 100644
index 00000000..5a99579c
--- /dev/null
+++ b/src/stats.cc
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2003-2009, John Wiegley. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of New Artisans LLC nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "derive.h"
+#include "xact.h"
+#include "post.h"
+#include "account.h"
+#include "report.h"
+#include "session.h"
+
+namespace ledger {
+
+value_t report_statistics(call_scope_t& args)
+{
+ report_t& report(find_scope<report_t>(args));
+ std::ostream& out(report.output_stream);
+
+ const account_t::xdata_t::details_t&
+ statistics(report.session.master->family_details(true));
+
+ if (! is_valid(statistics.earliest_post) &&
+ ! is_valid(statistics.latest_post))
+ return NULL_VALUE;
+
+ assert(is_valid(statistics.earliest_post));
+ assert(is_valid(statistics.latest_post));
+
+ {
+ straccstream accum;
+ out << ACCUM(accum << _("Time period: %1 to %2 (%3 days)")
+ << format_date(statistics.earliest_post)
+ << format_date(statistics.latest_post)
+ << (statistics.latest_post -
+ statistics.earliest_post).days())
+ << std::endl << std::endl;
+ }
+
+ out << _(" Files these postings came from:") << std::endl;
+
+ foreach (const path& pathname, statistics.filenames)
+ if (! pathname.empty())
+ out << " " << pathname.string() << std::endl;
+ out << std::endl;
+
+ out << _(" Unique payees: ");
+ out.width(6);
+ out << statistics.payees_referenced.size() << std::endl;
+
+ out << _(" Unique accounts: ");
+ out.width(6);
+ out << statistics.accounts_referenced.size() << std::endl;
+
+ out << std::endl;
+
+#if 0
+ out << _(" Number of transactions: ") ;
+ out.width(6);
+ out << statistics.xacts_count << std::endl;
+#endif
+
+ out << _(" Number of postings: ");
+ out.width(6);
+ out << statistics.posts_count;
+
+ out << " (";
+ out.precision(2);
+ out << (double((statistics.latest_post - statistics.earliest_post).days()) /
+ double(statistics.posts_count)) << _(" per day)") << std::endl;
+
+ out << _(" Uncleared postings: ");
+ out.width(6);
+ out << (statistics.posts_count -
+ statistics.posts_cleared_count) << std::endl;
+
+ out << std::endl;
+
+ out << _(" Days since last post: ");
+ out.width(6);
+ out << (CURRENT_DATE() - statistics.latest_post).days()
+ << std::endl;
+
+ out << _(" Posts in last 7 days: ");
+ out.width(6);
+ out << statistics.posts_last_7_count << std::endl;
+ out << _(" Posts in last 30 days: ");
+ out.width(6);
+ out << statistics.posts_last_30_count << std::endl;
+ out << _(" Posts seen this month: ");
+ out.width(6);
+ out << statistics.posts_this_month_count << std::endl;
+
+ out.flush();
+
+ return NULL_VALUE;
+}
+
+} // namespace ledger
diff --git a/src/stats.h b/src/stats.h
new file mode 100644
index 00000000..db8e9a0d
--- /dev/null
+++ b/src/stats.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2003-2009, John Wiegley. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of New Artisans LLC nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @addtogroup stats
+ */
+
+/**
+ * @file stats.h
+ * @author John Wiegley
+ *
+ * @ingroup report
+ *
+ * @brief Brief
+ *
+ * Long.
+ */
+#ifndef _STATS_H
+#define _STATS_H
+
+#include "value.h"
+
+namespace ledger {
+
+class call_scope_t;
+
+value_t report_statistics(call_scope_t& scope);
+
+} // namespace ledger
+
+#endif // _STATS_H