Redid the way temporaries are handled in filtering

This commit is contained in:
John Wiegley 2009-10-27 07:15:41 -04:00
parent f20b6a3b9e
commit 0fdb900c99
10 changed files with 325 additions and 172 deletions

View file

@ -76,6 +76,7 @@ libledger_report_la_SOURCES = \
src/precmd.cc \ src/precmd.cc \
src/chain.cc \ src/chain.cc \
src/filters.cc \ src/filters.cc \
src/temps.cc \
src/report.cc \ src/report.cc \
src/session.cc src/session.cc
@ -124,6 +125,7 @@ pkginclude_HEADERS = \
src/session.h \ src/session.h \
src/report.h \ src/report.h \
src/filters.h \ src/filters.h \
src/temps.h \
src/chain.h \ src/chain.h \
src/precmd.h \ src/precmd.h \
src/derive.h \ src/derive.h \

View file

@ -110,6 +110,14 @@ account_t * account_t::find_account_re(const string& regexp)
return find_account_re_(this, mask_t(regexp)); return find_account_re_(this, mask_t(regexp));
} }
bool account_t::remove_post(post_t * post)
{
assert(! posts.empty());
posts.remove(post);
post->account = NULL;
return true;
}
string account_t::fullname() const string account_t::fullname() const
{ {
if (! _fullname.empty()) { if (! _fullname.empty()) {
@ -140,7 +148,7 @@ string account_t::partial_name(bool flat) const
if (! flat) { if (! flat) {
std::size_t count = acct->children_with_flags(ACCOUNT_EXT_TO_DISPLAY); std::size_t count = acct->children_with_flags(ACCOUNT_EXT_TO_DISPLAY);
assert(count > 0); assert(count > 0);
if (count > 1 || acct->has_flags(ACCOUNT_EXT_TO_DISPLAY)) if (count > 1 || acct->has_xflags(ACCOUNT_EXT_TO_DISPLAY))
break; break;
} }
pname = acct->name + ":" + pname; pname = acct->name + ":" + pname;
@ -206,7 +214,7 @@ namespace {
acct = acct->parent) { acct = acct->parent) {
std::size_t count = acct->children_with_flags(ACCOUNT_EXT_TO_DISPLAY); std::size_t count = acct->children_with_flags(ACCOUNT_EXT_TO_DISPLAY);
assert(count > 0); assert(count > 0);
if (count > 1 || acct->has_flags(ACCOUNT_EXT_TO_DISPLAY)) if (count > 1 || acct->has_xflags(ACCOUNT_EXT_TO_DISPLAY))
depth++; depth++;
} }
@ -310,7 +318,7 @@ std::size_t account_t::children_with_flags(xdata_t::flags_t flags) const
bool grandchildren_visited = false; bool grandchildren_visited = false;
foreach (const accounts_map::value_type& pair, accounts) { foreach (const accounts_map::value_type& pair, accounts) {
if (pair.second->has_flags(flags) || if (pair.second->has_xflags(flags) ||
pair.second->children_with_flags(flags)) pair.second->children_with_flags(flags))
count++; count++;
} }
@ -362,20 +370,21 @@ account_t::xdata_t::details_t::operator+=(const details_t& other)
value_t account_t::self_total(const optional<expr_t&>& expr) const value_t account_t::self_total(const optional<expr_t&>& expr) const
{ {
if (xdata_ && xdata_->has_flags(ACCOUNT_EXT_VISITED)) { if (xdata_ && xdata_->has_flags(ACCOUNT_EXT_VISITED)) {
if (! xdata_) xdata_ = xdata_t(); posts_list::const_iterator i;
if (xdata_->self_details.last_post)
posts_deque::const_iterator i = i = *xdata_->self_details.last_post;
posts.begin() + xdata_->self_details.last_size; else
i = posts.begin();
for (; i != posts.end(); i++) { for (; i != posts.end(); i++) {
if ((*i)->xdata().has_flags(POST_EXT_VISITED) && if ((*i)->xdata().has_flags(POST_EXT_VISITED)) {
! (*i)->xdata().has_flags(POST_EXT_CONSIDERED)) { if (! (*i)->xdata().has_flags(POST_EXT_CONSIDERED)) {
(*i)->add_to_value(xdata_->self_details.total, expr); (*i)->add_to_value(xdata_->self_details.total, expr);
(*i)->xdata().add_flags(POST_EXT_CONSIDERED); (*i)->xdata().add_flags(POST_EXT_CONSIDERED);
} }
} }
xdata_->self_details.last_post = i;
xdata_->self_details.last_size = posts.size(); }
return xdata_->self_details.total; return xdata_->self_details.total;
} else { } else {

View file

@ -55,7 +55,7 @@ class account_t;
class xact_t; class xact_t;
class post_t; class post_t;
typedef std::deque<post_t *> posts_deque; typedef std::list<post_t *> posts_list;
typedef std::map<const string, account_t *> accounts_map; typedef std::map<const string, account_t *> accounts_map;
/** /**
@ -63,35 +63,37 @@ typedef std::map<const string, account_t *> accounts_map;
* *
* Long. * Long.
*/ */
class account_t : public scope_t class account_t : public supports_flags<>, public scope_t
{ {
public: #define ACCOUNT_NORMAL 0x00 // no flags at all, a basic account
#define ACCOUNT_KNOWN 0x01
#define ACCOUNT_TEMP 0x02 // account is a temporary object
public:
account_t * parent; account_t * parent;
string name; string name;
optional<string> note; optional<string> note;
unsigned short depth; unsigned short depth;
accounts_map accounts; accounts_map accounts;
posts_deque posts; posts_list posts;
bool known;
mutable string _fullname; mutable string _fullname;
account_t(account_t * _parent = NULL, account_t(account_t * _parent = NULL,
const string& _name = "", const string& _name = "",
const optional<string>& _note = none) const optional<string>& _note = none)
: scope_t(), parent(_parent), name(_name), note(_note), : supports_flags<>(), scope_t(), parent(_parent),
depth(static_cast<unsigned short>(parent ? parent->depth + 1 : 0)), name(_name), note(_note),
known(false) { depth(static_cast<unsigned short>(parent ? parent->depth + 1 : 0)) {
TRACE_CTOR(account_t, "account_t *, const string&, const string&"); TRACE_CTOR(account_t, "account_t *, const string&, const string&");
} }
account_t(const account_t& other) account_t(const account_t& other)
: scope_t(), : supports_flags<>(other.flags()), scope_t(),
parent(other.parent), parent(other.parent),
name(other.name), name(other.name),
note(other.note), note(other.note),
depth(other.depth), depth(other.depth),
accounts(other.accounts), accounts(other.accounts) {
known(other.known) {
TRACE_CTOR(account_t, "copy"); TRACE_CTOR(account_t, "copy");
} }
~account_t(); ~account_t();
@ -116,6 +118,7 @@ class account_t : public scope_t
void add_post(post_t * post) { void add_post(post_t * post) {
posts.push_back(post); posts.push_back(post);
} }
bool remove_post(post_t * post);
virtual expr_t::ptr_op_t lookup(const string& name); virtual expr_t::ptr_op_t lookup(const string& name);
@ -152,12 +155,12 @@ class account_t : public scope_t
date_t latest_post; date_t latest_post;
date_t latest_cleared_post; date_t latest_cleared_post;
std::size_t last_size;
std::set<path> filenames; std::set<path> filenames;
std::set<string> accounts_referenced; std::set<string> accounts_referenced;
std::set<string> payees_referenced; std::set<string> payees_referenced;
optional<posts_list::const_iterator> last_post;
details_t() details_t()
: calculated(false), : calculated(false),
gathered(false), gathered(false),
@ -167,9 +170,7 @@ class account_t : public scope_t
posts_cleared_count(0), posts_cleared_count(0),
posts_last_7_count(0), posts_last_7_count(0),
posts_last_30_count(0), posts_last_30_count(0),
posts_this_month_count(0), posts_this_month_count(0) {}
last_size(0) {}
details_t& operator+=(const details_t& other); details_t& operator+=(const details_t& other);
@ -227,7 +228,7 @@ class account_t : public scope_t
const xdata_t::details_t& self_details(bool gather_all = true) const; const xdata_t::details_t& self_details(bool gather_all = true) const;
const xdata_t::details_t& family_details(bool gather_all = true) const; const xdata_t::details_t& family_details(bool gather_all = true) const;
bool has_flags(xdata_t::flags_t flags) const { bool has_xflags(xdata_t::flags_t flags) const {
return xdata_ && xdata_->has_flags(flags); return xdata_ && xdata_->has_flags(flags);
} }
std::size_t children_with_flags(xdata_t::flags_t flags) const; std::size_t children_with_flags(xdata_t::flags_t flags) const;

View file

@ -140,11 +140,11 @@ void anonymize_posts::operator()(post_t& post)
bool copy_xact_details = false; bool copy_xact_details = false;
if (last_xact != post.xact) { if (last_xact != post.xact) {
xact_temps.push_back(*post.xact); temps.copy_xact(*post.xact);
last_xact = post.xact; last_xact = post.xact;
copy_xact_details = true; copy_xact_details = true;
} }
xact_t& xact = xact_temps.back(); xact_t& xact = temps.last_xact();
if (copy_xact_details) { if (copy_xact_details) {
xact.copy_details(*post.xact); xact.copy_details(*post.xact);
@ -157,10 +157,6 @@ void anonymize_posts::operator()(post_t& post)
xact.note = none; xact.note = none;
} }
post_temps.push_back(post);
post_t& temp = post_temps.back();
temp.xact = &xact;
std::list<string> account_names; std::list<string> account_names;
account_t * new_account = NULL; account_t * new_account = NULL;
@ -183,14 +179,8 @@ void anonymize_posts::operator()(post_t& post)
foreach (const string& name, account_names) foreach (const string& name, account_names)
new_account = new_account->find_account(name); new_account = new_account->find_account(name);
temp.copy_details(post); post_t& temp = temps.copy_post(post, xact, new_account);
temp.account = new_account;
temp.note = none; temp.note = none;
temp.add_flags(ITEM_TEMP);
temp.account->add_post(&temp);
xact.add_post(&temp);
(*handler)(temp); (*handler)(temp);
} }
@ -228,19 +218,14 @@ namespace {
void handle_value(const value_t& value, void handle_value(const value_t& value,
account_t * account, account_t * account,
xact_t * xact, xact_t * xact,
std::list<post_t>& temps, temporaries_t& temps,
item_handler<post_t>& handler, item_handler<post_t>& handler,
const date_t& date = date_t(), const date_t& date = date_t(),
const value_t& total = value_t(), const value_t& total = value_t(),
const bool direct_amount = false, const bool direct_amount = false,
const optional<post_functor_t>& functor = none) const optional<post_functor_t>& functor = none)
{ {
temps.push_back(post_t(account)); post_t& post = temps.create_post(*xact, account);
post_t& post(temps.back());
post.xact = xact;
post.add_flags(ITEM_TEMP);
post.account->add_post(&post);
xact->add_post(&post);
// If the account for this post is all virtual, then report the post as // If the account for this post is all virtual, then report the post as
// such. This allows subtotal reports to show "(Account)" for accounts // such. This allows subtotal reports to show "(Account)" for accounts
@ -327,14 +312,13 @@ void collapse_posts::report_subtotal()
earliest_date = reported; earliest_date = reported;
} }
xact_temps.push_back(xact_t()); xact_t& xact = temps.create_xact();
xact_t& xact = xact_temps.back();
xact.payee = last_xact->payee; xact.payee = last_xact->payee;
xact._date = (is_valid(earliest_date) ? xact._date = (is_valid(earliest_date) ?
earliest_date : last_xact->_date); earliest_date : last_xact->_date);
DEBUG("filter.collapse", "Pseudo-xact date = " << *xact._date); DEBUG("filter.collapse", "Pseudo-xact date = " << *xact._date);
handle_value(subtotal, &totals_account, &xact, post_temps, *handler); handle_value(subtotal, &totals_account, &xact, temps, *handler);
} }
component_posts.clear(); component_posts.clear();
@ -429,12 +413,11 @@ void changed_value_posts::output_revaluation(post_t * post, const date_t& date)
DEBUG("filter.changed_value", "output_revaluation(strip(diff)) = " DEBUG("filter.changed_value", "output_revaluation(strip(diff)) = "
<< diff.strip_annotations(report.what_to_keep())); << diff.strip_annotations(report.what_to_keep()));
xact_temps.push_back(xact_t()); xact_t& xact = temps.create_xact();
xact_t& xact = xact_temps.back();
xact.payee = _("Commodities revalued"); xact.payee = _("Commodities revalued");
xact._date = is_valid(date) ? date : post->date(); xact._date = is_valid(date) ? date : post->date();
handle_value(diff, &revalued_account, &xact, post_temps, *handler, handle_value(diff, &revalued_account, &xact, temps, *handler,
*xact._date, repriced_total, false, *xact._date, repriced_total, false,
optional<post_functor_t> optional<post_functor_t>
(bind(&changed_value_posts::output_rounding, this, _1))); (bind(&changed_value_posts::output_rounding, this, _1)));
@ -467,13 +450,12 @@ void changed_value_posts::output_rounding(post_t * post)
DEBUG("filter.changed_value.rounding", DEBUG("filter.changed_value.rounding",
"rounding.diff = " << diff); "rounding.diff = " << diff);
xact_temps.push_back(xact_t()); xact_t& xact = temps.create_xact();
xact_t& xact = xact_temps.back();
xact.payee = _("Commodity rounding"); xact.payee = _("Commodity rounding");
xact._date = post->date(); xact._date = post->date();
handle_value(diff, &rounding_account, &xact, post_temps, handle_value(diff, &rounding_account, &xact, temps, *handler,
*handler, *xact._date, precise_display_total, true); *xact._date, precise_display_total, true);
} }
} }
} }
@ -528,13 +510,12 @@ void subtotal_posts::report_subtotal(const char * spec_fmt,
out_date << "- " << format_date(*range_finish); out_date << "- " << format_date(*range_finish);
} }
xact_temps.push_back(xact_t()); xact_t& xact = temps.create_xact();
xact_t& xact = xact_temps.back();
xact.payee = out_date.str(); xact.payee = out_date.str();
xact._date = *range_start; xact._date = *range_start;
foreach (values_map::value_type& pair, values) foreach (values_map::value_type& pair, values)
handle_value(pair.second.value, pair.second.account, &xact, post_temps, handle_value(pair.second.value, pair.second.account, &xact, temps,
*handler); *handler);
values.clear(); values.clear();
@ -598,16 +579,12 @@ void interval_posts::operator()(post_t& post)
// Generate a null posting, so the intervening periods can be // Generate a null posting, so the intervening periods can be
// seen when -E is used, or if the calculated amount ends up being // seen when -E is used, or if the calculated amount ends up being
// non-zero // non-zero
xact_temps.push_back(xact_t()); xact_t& null_xact = temps.create_xact();
xact_t& null_xact = xact_temps.back();
null_xact.add_flags(ITEM_TEMP);
null_xact._date = last_interval.inclusive_end(); null_xact._date = last_interval.inclusive_end();
post_temps.push_back(post_t(&empty_account)); post_t& null_post = temps.create_post(null_xact, &empty_account);
post_t& null_post = post_temps.back(); null_post.add_flags(POST_CALCULATED);
null_post.add_flags(ITEM_TEMP | POST_CALCULATED);
null_post.amount = 0L; null_post.amount = 0L;
null_xact.add_post(&null_post);
last_post = &null_post; last_post = &null_post;
subtotal_posts::operator()(null_post); subtotal_posts::operator()(null_post);
@ -639,14 +616,13 @@ void posts_as_equity::report_subtotal()
} }
component_posts.clear(); component_posts.clear();
xact_temps.push_back(xact_t()); xact_t& xact = temps.create_xact();
xact_t& xact = xact_temps.back();
xact.payee = _("Opening Balances"); xact.payee = _("Opening Balances");
xact._date = finish; xact._date = finish;
value_t total = 0L; value_t total = 0L;
foreach (values_map::value_type& pair, values) { foreach (values_map::value_type& pair, values) {
handle_value(pair.second.value, pair.second.account, &xact, post_temps, handle_value(pair.second.value, pair.second.account, &xact, temps,
*handler); *handler);
total += pair.second.value; total += pair.second.value;
} }
@ -655,21 +631,13 @@ void posts_as_equity::report_subtotal()
if (total.is_balance()) { if (total.is_balance()) {
foreach (balance_t::amounts_map::value_type pair, foreach (balance_t::amounts_map::value_type pair,
total.as_balance().amounts) { total.as_balance().amounts) {
post_temps.push_back(post_t(balance_account)); post_t& balance_post = temps.create_post(xact, balance_account);
post_t& balance_post = post_temps.back();
balance_post.add_flags(ITEM_TEMP);
balance_post.amount = - pair.second; balance_post.amount = - pair.second;
balance_post.account->add_post(&balance_post);
xact.add_post(&balance_post);
(*handler)(balance_post); (*handler)(balance_post);
} }
} else { } else {
post_temps.push_back(post_t(balance_account)); post_t& balance_post = temps.create_post(xact, balance_account);
post_t& balance_post = post_temps.back();
balance_post.add_flags(ITEM_TEMP);
balance_post.amount = - total.to_amount(); balance_post.amount = - total.to_amount();
balance_post.account->add_post(&balance_post);
xact.add_post(&balance_post);
(*handler)(balance_post); (*handler)(balance_post);
} }
} }
@ -705,17 +673,11 @@ void by_payee_posts::operator()(post_t& post)
void transfer_details::operator()(post_t& post) void transfer_details::operator()(post_t& post)
{ {
xact_temps.push_back(*post.xact); xact_t& xact = temps.copy_xact(*post.xact);
xact_t& xact = xact_temps.back();
xact._date = post.date(); xact._date = post.date();
post_temps.push_back(post); post_t& temp = temps.copy_post(post, xact);
post_t& temp = post_temps.back();
temp.xact = &xact;
temp.set_state(post.state()); temp.set_state(post.state());
temp.add_flags(ITEM_TEMP);
temp.account->add_post(&temp);
xact.add_post(&temp);
bind_scope_t bound_scope(scope, temp); bind_scope_t bound_scope(scope, temp);
@ -725,6 +687,7 @@ void transfer_details::operator()(post_t& post)
break; break;
case SET_ACCOUNT: case SET_ACCOUNT:
temp.account = master->find_account(expr.calc(bound_scope).to_string()); temp.account = master->find_account(expr.calc(bound_scope).to_string());
temp.account->add_post(&temp);
break; break;
default: default:
assert(false); assert(false);
@ -782,18 +745,12 @@ void budget_posts::report_budget_items(const date_t& date)
DEBUG("ledger.walk.budget", "Reporting budget for " DEBUG("ledger.walk.budget", "Reporting budget for "
<< post.reported_account()->fullname()); << post.reported_account()->fullname());
xact_temps.push_back(xact_t()); xact_t& xact = temps.create_xact();
xact_t& xact = xact_temps.back();
xact.payee = _("Budget transaction"); xact.payee = _("Budget transaction");
xact._date = begin; xact._date = begin;
post_temps.push_back(post); post_t& temp = temps.copy_post(post, xact);
post_t& temp = post_temps.back();
temp.xact = &xact;
temp.add_flags(ITEM_TEMP);
temp.amount.in_place_negate(); temp.amount.in_place_negate();
temp.account->add_post(&temp);
xact.add_post(&temp);
++pair.first; ++pair.first;
begin = *pair.first.start; begin = *pair.first.start;
@ -816,8 +773,8 @@ void budget_posts::operator()(post_t& post)
acct = acct->parent) { acct = acct->parent) {
if (acct == (*pair.second).reported_account()) { if (acct == (*pair.second).reported_account()) {
post_in_budget = true; post_in_budget = true;
// Report the post as if it had occurred in the parent // Report the post as if it had occurred in the parent account.
// account. // jww (2009-10-27): What about calling add_post here?
if (post.reported_account() != acct) if (post.reported_account() != acct)
post.xdata().account = acct; post.xdata().account = acct;
goto handle; goto handle;
@ -873,17 +830,11 @@ void forecast_posts::flush()
post_t& post = *(*least).second; post_t& post = *(*least).second;
xact_temps.push_back(xact_t()); xact_t& xact = temps.create_xact();
xact_t& xact = xact_temps.back();
xact.payee = _("Forecast transaction"); xact.payee = _("Forecast transaction");
xact._date = begin; xact._date = begin;
post_temps.push_back(post); post_t& temp = temps.copy_post(post, xact);
post_t& temp = post_temps.back();
temp.xact = &xact;
temp.add_flags(ITEM_TEMP);
temp.account->add_post(&temp);
xact.add_post(&temp);
date_t next = *(*least).first.next; date_t next = *(*least).first.next;
++(*least).first; ++(*least).first;

View file

@ -50,6 +50,7 @@
#include "xact.h" #include "xact.h"
#include "post.h" #include "post.h"
#include "account.h" #include "account.h"
#include "temps.h"
namespace ledger { namespace ledger {
@ -279,11 +280,6 @@ public:
} }
}; };
inline void clear_xacts_posts(std::list<xact_t>& xacts_list) {
foreach (xact_t& xact, xacts_list)
xact.posts.clear();
}
/** /**
* @brief Brief * @brief Brief
* *
@ -291,8 +287,7 @@ inline void clear_xacts_posts(std::list<xact_t>& xacts_list) {
*/ */
class anonymize_posts : public item_handler<post_t> class anonymize_posts : public item_handler<post_t>
{ {
std::list<xact_t> xact_temps; temporaries_t temps;
std::list<post_t> post_temps;
xact_t * last_xact; xact_t * last_xact;
@ -305,7 +300,6 @@ public:
} }
virtual ~anonymize_posts() { virtual ~anonymize_posts() {
TRACE_DTOR(anonymize_posts); TRACE_DTOR(anonymize_posts);
clear_xacts_posts(xact_temps);
} }
virtual void operator()(post_t& post); virtual void operator()(post_t& post);
@ -353,11 +347,9 @@ class collapse_posts : public item_handler<post_t>
std::size_t count; std::size_t count;
xact_t * last_xact; xact_t * last_xact;
post_t * last_post; post_t * last_post;
account_t totals_account; temporaries_t temps;
account_t& totals_account;
bool only_collapse_if_zero; bool only_collapse_if_zero;
std::list<xact_t> xact_temps;
std::list<post_t> post_temps;
std::list<post_t *> component_posts; std::list<post_t *> component_posts;
collapse_posts(); collapse_posts();
@ -372,13 +364,12 @@ public:
display_predicate(_display_predicate), display_predicate(_display_predicate),
only_predicate(_only_predicate), count(0), only_predicate(_only_predicate), count(0),
last_xact(NULL), last_post(NULL), last_xact(NULL), last_post(NULL),
totals_account(NULL, _("<Total>")), totals_account(temps.create_account(_("<Total>"))),
only_collapse_if_zero(_only_collapse_if_zero) { only_collapse_if_zero(_only_collapse_if_zero) {
TRACE_CTOR(collapse_posts, "post_handler_ptr"); TRACE_CTOR(collapse_posts, "post_handler_ptr");
} }
virtual ~collapse_posts() { virtual ~collapse_posts() {
TRACE_DTOR(collapse_posts); TRACE_DTOR(collapse_posts);
clear_xacts_posts(xact_temps);
} }
virtual void flush() { virtual void flush() {
@ -440,11 +431,9 @@ class changed_value_posts : public item_handler<post_t>
post_t * last_post; post_t * last_post;
value_t last_total; value_t last_total;
value_t last_display_total; value_t last_display_total;
account_t revalued_account; temporaries_t temps;
account_t rounding_account; account_t& revalued_account;
account_t& rounding_account;
std::list<xact_t> xact_temps;
std::list<post_t> post_temps;
changed_value_posts(); changed_value_posts();
@ -459,14 +448,13 @@ public:
display_amount_expr(_display_amount_expr), total_expr(_total_expr), display_amount_expr(_display_amount_expr), total_expr(_total_expr),
display_total_expr(_display_total_expr), report(_report), display_total_expr(_display_total_expr), report(_report),
changed_values_only(_changed_values_only), last_post(NULL), changed_values_only(_changed_values_only), last_post(NULL),
revalued_account(NULL, _("<Revalued>")), revalued_account(temps.create_account(_("<Revalued>"))),
rounding_account(NULL, _("<Rounding>")){ rounding_account(temps.create_account(_("<Rounding>"))) {
TRACE_CTOR(changed_value_posts, TRACE_CTOR(changed_value_posts,
"post_handler_ptr, const expr_t&, const expr_t&, report_t&, bool"); "post_handler_ptr, const expr_t&, const expr_t&, report_t&, bool");
} }
virtual ~changed_value_posts() { virtual ~changed_value_posts() {
TRACE_DTOR(changed_value_posts); TRACE_DTOR(changed_value_posts);
clear_xacts_posts(xact_temps);
} }
virtual void flush(); virtual void flush();
@ -517,8 +505,7 @@ protected:
expr_t& amount_expr; expr_t& amount_expr;
values_map values; values_map values;
optional<string> date_format; optional<string> date_format;
std::list<xact_t> xact_temps; temporaries_t temps;
std::list<post_t> post_temps;
std::list<post_t *> component_posts; std::list<post_t *> component_posts;
public: public:
@ -531,7 +518,6 @@ public:
} }
virtual ~subtotal_posts() { virtual ~subtotal_posts() {
TRACE_DTOR(subtotal_posts); TRACE_DTOR(subtotal_posts);
clear_xacts_posts(xact_temps);
} }
void report_subtotal(const char * spec_fmt = NULL, void report_subtotal(const char * spec_fmt = NULL,
@ -555,7 +541,7 @@ class interval_posts : public subtotal_posts
date_interval_t interval; date_interval_t interval;
date_interval_t last_interval; date_interval_t last_interval;
post_t * last_post; post_t * last_post;
account_t empty_account; account_t& empty_account;
bool exact_periods; bool exact_periods;
bool generate_empty_posts; bool generate_empty_posts;
@ -569,11 +555,11 @@ public:
bool _exact_periods = false, bool _exact_periods = false,
bool _generate_empty_posts = false) bool _generate_empty_posts = false)
: subtotal_posts(_handler, amount_expr), interval(_interval), : subtotal_posts(_handler, amount_expr), interval(_interval),
last_post(NULL), empty_account(NULL, _("<None>")), last_post(NULL), empty_account(temps.create_account(_("<None>"))),
exact_periods(_exact_periods), exact_periods(_exact_periods),
generate_empty_posts(_generate_empty_posts) { generate_empty_posts(_generate_empty_posts) {
TRACE_CTOR(interval_posts, TRACE_CTOR(interval_posts,
"post_handler_ptr, expr_t&, interval_t, account_t *, bool, bool"); "post_handler_ptr, expr_t&, date_interval_t, bool, bool");
} }
virtual ~interval_posts() throw() { virtual ~interval_posts() throw() {
TRACE_DTOR(interval_posts); TRACE_DTOR(interval_posts);
@ -594,7 +580,7 @@ public:
class posts_as_equity : public subtotal_posts class posts_as_equity : public subtotal_posts
{ {
post_t * last_post; post_t * last_post;
account_t equity_account; account_t& equity_account;
account_t * balance_account; account_t * balance_account;
posts_as_equity(); posts_as_equity();
@ -602,7 +588,7 @@ class posts_as_equity : public subtotal_posts
public: public:
posts_as_equity(post_handler_ptr _handler, expr_t& amount_expr) posts_as_equity(post_handler_ptr _handler, expr_t& amount_expr)
: subtotal_posts(_handler, amount_expr), : subtotal_posts(_handler, amount_expr),
equity_account(NULL, _("Equity")) { equity_account(temps.create_account(_("Equity"))) {
TRACE_CTOR(posts_as_equity, "post_handler_ptr, expr_t&"); TRACE_CTOR(posts_as_equity, "post_handler_ptr, expr_t&");
balance_account = equity_account.find_account(_("Opening Balances")); balance_account = equity_account.find_account(_("Opening Balances"));
} }
@ -653,11 +639,10 @@ class by_payee_posts : public item_handler<post_t>
*/ */
class transfer_details : public item_handler<post_t> class transfer_details : public item_handler<post_t>
{ {
std::list<xact_t> xact_temps;
std::list<post_t> post_temps;
account_t * master; account_t * master;
expr_t expr; expr_t expr;
scope_t& scope; scope_t& scope;
temporaries_t temps;
transfer_details(); transfer_details();
@ -679,7 +664,6 @@ public:
} }
virtual ~transfer_details() { virtual ~transfer_details() {
TRACE_DTOR(transfer_details); TRACE_DTOR(transfer_details);
clear_xacts_posts(xact_temps);
} }
virtual void operator()(post_t& post); virtual void operator()(post_t& post);
@ -725,8 +709,7 @@ protected:
typedef std::list<pending_posts_pair> pending_posts_list; typedef std::list<pending_posts_pair> pending_posts_list;
pending_posts_list pending_posts; pending_posts_list pending_posts;
std::list<xact_t> xact_temps; temporaries_t temps;
std::list<post_t> post_temps;
public: public:
generate_posts(post_handler_ptr handler) generate_posts(post_handler_ptr handler)
@ -736,7 +719,6 @@ public:
virtual ~generate_posts() { virtual ~generate_posts() {
TRACE_DTOR(generate_posts); TRACE_DTOR(generate_posts);
clear_xacts_posts(xact_temps);
} }
void add_period_xacts(period_xacts_list& period_xacts); void add_period_xacts(period_xacts_list& period_xacts);

View file

@ -169,7 +169,7 @@ format_accounts::mark_accounts(account_t& account, const bool flat)
#if defined(DEBUG_ON) #if defined(DEBUG_ON)
DEBUG("account.display", "Considering account: " << account.fullname()); DEBUG("account.display", "Considering account: " << account.fullname());
if (account.has_flags(ACCOUNT_EXT_VISITED)) if (account.has_xflags(ACCOUNT_EXT_VISITED))
DEBUG("account.display", " it was visited itself"); DEBUG("account.display", " it was visited itself");
DEBUG("account.display", " it has " << visited << " visited children"); DEBUG("account.display", " it has " << visited << " visited children");
DEBUG("account.display", DEBUG("account.display",
@ -177,11 +177,11 @@ format_accounts::mark_accounts(account_t& account, const bool flat)
#endif #endif
if (account.parent && if (account.parent &&
(account.has_flags(ACCOUNT_EXT_VISITED) || (! flat && visited > 0))) { (account.has_xflags(ACCOUNT_EXT_VISITED) || (! flat && visited > 0))) {
bind_scope_t bound_scope(report, account); bind_scope_t bound_scope(report, account);
if ((! flat && to_display > 1) || if ((! flat && to_display > 1) ||
((flat || to_display != 1 || ((flat || to_display != 1 ||
account.has_flags(ACCOUNT_EXT_VISITED)) && account.has_xflags(ACCOUNT_EXT_VISITED)) &&
disp_pred(bound_scope))) { disp_pred(bound_scope))) {
account.xdata().add_flags(ACCOUNT_EXT_TO_DISPLAY); account.xdata().add_flags(ACCOUNT_EXT_TO_DISPLAY);
DEBUG("account.display", "Marking account as TO_DISPLAY"); DEBUG("account.display", "Marking account as TO_DISPLAY");

124
src/temps.cc Normal file
View file

@ -0,0 +1,124 @@
/*
* 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 <system.hh>
#include "temps.h"
namespace ledger {
temporaries_t::~temporaries_t()
{
if (post_temps) {
foreach (post_t& post, *post_temps) {
if (! post.xact->has_flags(ITEM_TEMP))
post.xact->remove_post(&post);
if (! post.account->has_flags(ACCOUNT_TEMP))
post.account->remove_post(&post);
}
}
}
xact_t& temporaries_t::copy_xact(xact_t& origin)
{
if (! xact_temps)
xact_temps = std::list<xact_t>();
xact_temps->push_back(origin);
xact_t& temp(xact_temps->back());
temp.add_flags(ITEM_TEMP);
return temp;
}
xact_t& temporaries_t::create_xact()
{
if (! xact_temps)
xact_temps = std::list<xact_t>();
xact_temps->push_back(xact_t());
xact_t& temp(xact_temps->back());
temp.add_flags(ITEM_TEMP);
return temp;
}
post_t& temporaries_t::copy_post(post_t& origin, xact_t& xact,
account_t * account)
{
if (! post_temps)
post_temps = std::list<post_t>();
post_temps->push_back(origin);
post_t& temp(post_temps->back());
if (account)
temp.account = account;
temp.add_flags(ITEM_TEMP);
temp.account->add_post(&temp);
xact.add_post(&temp);
return temp;
}
post_t& temporaries_t::create_post(xact_t& xact, account_t * account)
{
if (! post_temps)
post_temps = std::list<post_t>();
post_temps->push_back(post_t(account));
post_t& temp(post_temps->back());
temp.account = account;
temp.add_flags(ITEM_TEMP);
temp.account->add_post(&temp);
xact.add_post(&temp);
return temp;
}
account_t& temporaries_t::create_account(const string& name,
account_t * parent)
{
if (! acct_temps)
acct_temps = std::list<account_t>();
acct_temps->push_back(account_t(parent, name));
account_t& temp(acct_temps->back());
temp.add_flags(ACCOUNT_TEMP);
return temp;
}
} // namespace ledger

84
src/temps.h Normal file
View file

@ -0,0 +1,84 @@
/*
* 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 report
*/
/**
* @file temps.h
* @author John Wiegley
*
* @ingroup report
*
* @brief Brief
*
* Long.
*/
#ifndef _TEMPS_H
#define _TEMPS_H
#include "xact.h"
#include "post.h"
#include "account.h"
namespace ledger {
class temporaries_t
{
optional<std::list<xact_t> > xact_temps;
optional<std::list<post_t> > post_temps;
optional<std::list<account_t> > acct_temps;
public:
~temporaries_t();
xact_t& copy_xact(xact_t& origin);
xact_t& create_xact();
xact_t& last_xact() {
return xact_temps->back();
}
post_t& copy_post(post_t& origin, xact_t& xact,
account_t * account = NULL);
post_t& create_post(xact_t& xact, account_t * account);
post_t& last_post() {
return post_temps->back();
}
account_t& create_account(const string& name,
account_t * parent = NULL);
account_t& last_account() {
return acct_temps->back();
}
};
} // namespace ledger
#endif // _TEMPS_H

View file

@ -446,7 +446,7 @@ void instance_t::default_commodity_directive(char * line)
void instance_t::default_account_directive(char * line) void instance_t::default_account_directive(char * line)
{ {
journal.basket = account_stack.front()->find_account(skip_ws(line + 1)); journal.basket = account_stack.front()->find_account(skip_ws(line + 1));
journal.basket->known = true; journal.basket->add_flags(ACCOUNT_KNOWN);
} }
void instance_t::price_conversion_directive(char * line) void instance_t::price_conversion_directive(char * line)
@ -845,11 +845,11 @@ post_t * instance_t::parse_post(char * line,
if (! post->account) if (! post->account)
post->account = account->find_account(name); post->account = account->find_account(name);
if (honor_strict && strict && ! post->account->known) { if (honor_strict && strict && ! post->account->has_flags(ACCOUNT_KNOWN)) {
if (post->_state == item_t::UNCLEARED) if (post->_state == item_t::UNCLEARED)
warning_(_("\"%1\", line %2: Unknown account '%3'") warning_(_("\"%1\", line %2: Unknown account '%3'")
<< pathname << linenum << post->account->fullname()); << pathname << linenum << post->account->fullname());
post->account->known = true; post->account->add_flags(ACCOUNT_KNOWN);
} }
// Parse the optional amount // Parse the optional amount