summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/filters.cc43
-rw-r--r--src/filters.h50
2 files changed, 92 insertions, 1 deletions
diff --git a/src/filters.cc b/src/filters.cc
index 57c95cd3..6915144d 100644
--- a/src/filters.cc
+++ b/src/filters.cc
@@ -39,8 +39,49 @@
namespace ledger {
+void post_splitter::print_title(const value_t& val)
+{
+ if (! report.HANDLED(no_titles)) {
+ std::ostringstream buf;
+ val.print(buf);
+ post_chain->title(buf.str());
+ }
+}
+
+void post_splitter::flush()
+{
+ foreach (value_to_posts_map::value_type pair, posts_map) {
+ preflush_func(pair.first);
+
+ foreach (post_t * post, pair.second)
+ (*post_chain)(*post);
+
+ post_chain->flush();
+ post_chain->clear();
+
+ if (postflush_func)
+ (*postflush_func)(pair.first);
+ }
+}
+
+void post_splitter::operator()(post_t& post)
+{
+ bind_scope_t bound_scope(report, post);
+ value_t result(group_by_expr.calc(bound_scope));
+
+ value_to_posts_map::iterator i = posts_map.find(result);
+ if (i != posts_map.end()) {
+ (*i).second.push_back(&post);
+ } else {
+ std::pair<value_to_posts_map::iterator, bool> inserted
+ = posts_map.insert(value_to_posts_map::value_type(result, posts_list()));
+ assert(inserted.second);
+ (*inserted.first).second.push_back(&post);
+ }
+}
+
pass_down_posts::pass_down_posts(post_handler_ptr handler,
- posts_iterator& iter)
+ posts_iterator& iter)
: item_handler<post_t>(handler)
{
TRACE_CTOR(pass_down_posts, "post_handler_ptr, posts_iterator");
diff --git a/src/filters.h b/src/filters.h
index 3f3e3d34..dd6b3b1a 100644
--- a/src/filters.h
+++ b/src/filters.h
@@ -52,6 +52,56 @@ namespace ledger {
//////////////////////////////////////////////////////////////////////
//
+// Posting collector
+//
+
+class post_splitter : public item_handler<post_t>
+{
+public:
+ typedef std::map<value_t, posts_list> value_to_posts_map;
+ typedef function<void (const value_t&)> custom_flusher_t;
+
+protected:
+ value_to_posts_map posts_map;
+ report_t& report;
+ post_handler_ptr post_chain;
+ expr_t group_by_expr;
+ custom_flusher_t preflush_func;
+ optional<custom_flusher_t> postflush_func;
+
+public:
+ post_splitter(report_t& _report,
+ post_handler_ptr _post_chain,
+ expr_t _group_by_expr)
+ : report(_report), post_chain(_post_chain),
+ group_by_expr(_group_by_expr),
+ preflush_func(bind(&post_splitter::print_title, this, _1)) {
+ TRACE_CTOR(post_splitter, "scope_t&, post_handler_ptr, expr_t");
+ }
+ virtual ~post_splitter() {
+ TRACE_DTOR(post_splitter);
+ }
+
+ void set_preflush_func(custom_flusher_t functor) {
+ preflush_func = functor;
+ }
+ void set_postflush_func(custom_flusher_t functor) {
+ postflush_func = functor;
+ }
+
+ virtual void print_title(const value_t& val);
+
+ virtual void flush();
+ virtual void operator()(post_t& post);
+
+ virtual void clear() {
+ posts_map.clear();
+ post_chain->clear();
+ }
+};
+
+//////////////////////////////////////////////////////////////////////
+//
// Posting filters
//