Pounded the logging and memory tracing code into better shape.

This commit is contained in:
John Wiegley 2007-04-27 10:09:14 +00:00
parent d0e9822ed1
commit a85bd282d7
16 changed files with 527 additions and 287 deletions

View file

@ -180,18 +180,11 @@ if HAVE_LIBOFX
PYLIBS += ofx
endif
if DEBUG
DEBUG_LEVEL = 4
else
DEBUG_LEVEL = 0
endif
ledger.so: pyledger.cc libledger.la gdtoa/libgdtoa.la libpyledger.la
SRCDIR="$(srcdir)" \
CFLAGS="$(CPPFLAGS) -I$(srcdir) $(libledger_la_CPPFLAGS)" \
LDFLAGS="$(LDFLAGS) -L. -L.libs -Lgdtoa -Lgdtoa/.libs" \
PYLIBS="$(PYLIBS)" \
DEBUG_LEVEL="$(DEBUG_LEVEL)" \
python $(srcdir)/setup.py build --build-lib=.
install-exec-hook:
@ -199,7 +192,6 @@ install-exec-hook:
CFLAGS="$(CPPFLAGS) -I$(srcdir) $(libledger_la_CPPFLAGS)" \
LDFLAGS="$(LDFLAGS) -L. -L.libs -Lgdtoa -Lgdtoa/.libs" \
PYLIBS="$(PYLIBS)" \
DEBUG_LEVEL="$(DEBUG_LEVEL)" \
python $(srcdir)/setup.py install --prefix=$(prefix)
endif

View file

@ -418,8 +418,6 @@ lisp_LISP = ledger.el timeclock.el
@HAVE_BOOST_PYTHON_TRUE@ boost_regex boost_python gmp \
@HAVE_BOOST_PYTHON_TRUE@ $(am__append_14) $(am__append_15) \
@HAVE_BOOST_PYTHON_TRUE@ $(am__append_16)
@DEBUG_FALSE@@HAVE_BOOST_PYTHON_TRUE@DEBUG_LEVEL = 0
@DEBUG_TRUE@@HAVE_BOOST_PYTHON_TRUE@DEBUG_LEVEL = 4
UnitTests_SOURCES = tests/UnitTests.cc \
\
tests/corelib/numerics/BasicAmount.cc \
@ -1723,7 +1721,6 @@ dist-hook:
@HAVE_BOOST_PYTHON_TRUE@ CFLAGS="$(CPPFLAGS) -I$(srcdir) $(libledger_la_CPPFLAGS)" \
@HAVE_BOOST_PYTHON_TRUE@ LDFLAGS="$(LDFLAGS) -L. -L.libs -Lgdtoa -Lgdtoa/.libs" \
@HAVE_BOOST_PYTHON_TRUE@ PYLIBS="$(PYLIBS)" \
@HAVE_BOOST_PYTHON_TRUE@ DEBUG_LEVEL="$(DEBUG_LEVEL)" \
@HAVE_BOOST_PYTHON_TRUE@ python $(srcdir)/setup.py build --build-lib=.
@HAVE_BOOST_PYTHON_TRUE@install-exec-hook:
@ -1731,7 +1728,6 @@ dist-hook:
@HAVE_BOOST_PYTHON_TRUE@ CFLAGS="$(CPPFLAGS) -I$(srcdir) $(libledger_la_CPPFLAGS)" \
@HAVE_BOOST_PYTHON_TRUE@ LDFLAGS="$(LDFLAGS) -L. -L.libs -Lgdtoa -Lgdtoa/.libs" \
@HAVE_BOOST_PYTHON_TRUE@ PYLIBS="$(PYLIBS)" \
@HAVE_BOOST_PYTHON_TRUE@ DEBUG_LEVEL="$(DEBUG_LEVEL)" \
@HAVE_BOOST_PYTHON_TRUE@ python $(srcdir)/setup.py install --prefix=$(prefix)
PyUnitTests: PyUnitTests.py

View file

@ -106,11 +106,11 @@ base_commodities_map commodity_base_t::commodities;
commodity_base_t::updater_t * commodity_base_t::updater = NULL;
commodities_map commodity_t::commodities;
commodities_array commodity_t::commodities_by_ident;
bool commodity_t::commodities_sorted = false;
commodity_t * commodity_t::null_commodity;
commodity_t * commodity_t::default_commodity = NULL;
commodities_map commodity_t::commodities;
commodities_array * commodity_t::commodities_by_ident;
bool commodity_t::commodities_sorted = false;
commodity_t * commodity_t::null_commodity;
commodity_t * commodity_t::default_commodity = NULL;
#endif
void amount_t::initialize()
@ -123,6 +123,8 @@ void amount_t::initialize()
commodity_base_t::updater = NULL;
commodity_t::commodities_by_ident = new commodities_array;
commodity_t::default_commodity = NULL;
commodity_t::null_commodity = commodity_t::create("");
commodity_t::null_commodity->add_flags(COMMODITY_STYLE_NOMARKET |
@ -159,7 +161,9 @@ void amount_t::shutdown()
commodity_base_t::commodities.clear();
commodity_t::commodities.clear();
commodity_t::commodities_by_ident.clear();
delete commodity_t::commodities_by_ident;
commodity_t::commodities_by_ident = NULL;
commodity_t::null_commodity = NULL;
commodity_t::default_commodity = NULL;
@ -337,7 +341,7 @@ amount_t::amount_t(const double val)
void amount_t::_release()
{
DEBUG_("amounts.refs",
quantity << " ref--, now " << (quantity->ref - 1));
quantity << " ref--, now " << (quantity->ref - 1));
if (--quantity->ref == 0) {
if (! (quantity->flags & BIGINT_BULK_ALLOC))
delete quantity;
@ -379,7 +383,7 @@ void amount_t::_copy(const amount_t& amt)
} else {
quantity = amt.quantity;
DEBUG_("amounts.refs",
quantity << " ref++, now " << (quantity->ref + 1));
quantity << " ref++, now " << (quantity->ref + 1));
quantity->ref++;
}
}
@ -1211,10 +1215,10 @@ bool parse_annotations(std::istream& in, amount_t& price,
} while (true);
DEBUG_("amounts.commodities",
"Parsed commodity annotations: "
<< " price " << price << " "
<< " date " << date << " "
<< " tag " << tag);
"Parsed commodity annotations: "
<< " price " << price << " "
<< " date " << date << " "
<< " tag " << tag);
return has_date;
}
@ -1401,7 +1405,7 @@ void amount_t::read(std::istream& in)
else if (ident == 0)
commodity_ = commodity_t::null_commodity;
else
commodity_ = commodity_t::commodities_by_ident[ident - 1];
commodity_ = (*commodity_t::commodities_by_ident)[ident - 1];
read_quantity(in);
}
@ -1415,7 +1419,7 @@ void amount_t::read(char *& data)
else if (ident == 0)
commodity_ = commodity_t::null_commodity;
else
commodity_ = commodity_t::commodities_by_ident[ident - 1];
commodity_ = (*commodity_t::commodities_by_ident)[ident - 1];
read_quantity(data);
}
@ -1470,7 +1474,7 @@ void amount_t::read_quantity(char *& data)
quantity = (bigint_t *) (bigints + (index - 1) * sizeof(bigint_t));
DEBUG_("amounts.refs",
quantity << " ref++, now " << (quantity->ref + 1));
quantity << " ref++, now " << (quantity->ref + 1));
quantity->ref++;
}
}
@ -1585,10 +1589,10 @@ void amount_t::annotate_commodity(const amount_t& tprice,
assert(this_base);
DEBUG_("amounts.commodities", "Annotating commodity for amount "
<< *this << std::endl
<< " price " << tprice << " "
<< " date " << tdate << " "
<< " tag " << tag);
<< *this << std::endl
<< " price " << tprice << " "
<< " date " << tdate << " "
<< " tag " << tag);
commodity_t * ann_comm =
annotated_commodity_t::find_or_create
@ -1610,10 +1614,10 @@ amount_t amount_t::strip_annotations(const bool _keep_price,
return *this;
DEBUG_("amounts.commodities", "Reducing commodity for amount "
<< *this << std::endl
<< " keep price " << _keep_price << " "
<< " keep date " << _keep_date << " "
<< " keep tag " << _keep_tag);
<< *this << std::endl
<< " keep price " << _keep_price << " "
<< " keep date " << _keep_date << " "
<< " keep tag " << _keep_tag);
annotated_commodity_t&
ann_comm(static_cast<annotated_commodity_t&>(commodity()));
@ -1647,7 +1651,7 @@ amount_t amount_t::price() const
amount_t t(((annotated_commodity_t *)commodity_)->price);
t *= number();
DEBUG_("amounts.commodities",
"Returning price of " << *this << " = " << t);
"Returning price of " << *this << " = " << t);
return t;
}
return *this;
@ -1657,8 +1661,8 @@ moment_t amount_t::date() const
{
if (commodity_ && commodity_->annotated) {
DEBUG_("amounts.commodities",
"Returning date of " << *this << " = "
<< ((annotated_commodity_t *)commodity_)->date);
"Returning date of " << *this << " = "
<< ((annotated_commodity_t *)commodity_)->date);
return ((annotated_commodity_t *)commodity_)->date;
}
return moment_t();
@ -1720,7 +1724,7 @@ bool commodity_t::valid() const
{
if (symbol().empty() && this != null_commodity) {
DEBUG_("ledger.validate",
"commodity_t: symbol().empty() && this != null_commodity");
"commodity_t: symbol().empty() && this != null_commodity");
return false;
}
@ -1752,15 +1756,15 @@ commodity_t * commodity_t::create(const string& symbol)
}
DEBUG_("amounts.commodities",
"Creating commodity " << commodity->qualified_symbol);
"Creating commodity " << commodity->qualified_symbol);
std::pair<commodities_map::iterator, bool> result
= commodities.insert(commodities_pair(symbol, commodity.get()));
if (! result.second)
return NULL;
commodity->ident = commodities_by_ident.size();
commodities_by_ident.push_back(commodity.get());
commodity->ident = commodities_by_ident->size();
commodities_by_ident->push_back(commodity.get());
// Start out the new commodity with the default commodity's flags
// and precision, if one has been defined.
@ -1896,11 +1900,11 @@ annotated_commodity_t::create(const commodity_t& comm,
commodity->qualified_symbol = comm.symbol();
DEBUG_("amounts.commodities", "Creating annotated commodity "
<< "symbol " << commodity->symbol()
<< " key " << mapping_key << std::endl
<< " price " << price << " "
<< " date " << date << " "
<< " tag " << tag);
<< "symbol " << commodity->symbol()
<< " key " << mapping_key << std::endl
<< " price " << price << " "
<< " date " << date << " "
<< " tag " << tag);
// Add the fully annotated name to the map, so that this symbol may
// quickly be found again.
@ -1909,8 +1913,8 @@ annotated_commodity_t::create(const commodity_t& comm,
if (! result.second)
return NULL;
commodity->ident = commodities_by_ident.size();
commodities_by_ident.push_back(commodity.get());
commodity->ident = commodities_by_ident->size();
commodities_by_ident->push_back(commodity.get());
return commodity.release();
}
@ -1931,10 +1935,10 @@ namespace {
annotated_commodity_t::write_annotations(name, price, date, tag);
DEBUG_("amounts.commodities", "make_qualified_name for "
<< comm.qualified_symbol << std::endl
<< " price " << price << " "
<< " date " << date << " "
<< " tag " << tag);
<< comm.qualified_symbol << std::endl
<< " price " << price << " "
<< " date " << date << " "
<< " tag " << tag);
DEBUG_("amounts.commodities", "qualified_name is " << name.str());

View file

@ -554,11 +554,11 @@ class commodity_t
public:
// This map remembers all commodities that have been defined.
static commodities_map commodities;
static commodities_array commodities_by_ident;
static bool commodities_sorted;
static commodity_t * null_commodity;
static commodity_t * default_commodity;
static commodities_map commodities;
static commodities_array * commodities_by_ident;
static bool commodities_sorted;
static commodity_t * null_commodity;
static commodity_t * default_commodity;
static commodity_t * create(const string& symbol);
static commodity_t * find(const string& name);

View file

@ -4,7 +4,7 @@ namespace ledger {
#if 0
static unsigned long binary_magic_number = 0xFFEED765;
#ifdef DEBUG_ENABLED
#if defined(DEBUG_ON)
static unsigned long format_version = 0x00030000;
#else
static unsigned long format_version = 0x00030000;

55
main.cc
View file

@ -67,8 +67,8 @@ static int read_and_report(report_t * report, int argc, char * argv[],
TRACE(1, "Binary cache is " << session.cache_file);
TRACE(1, "Main journal is " << session.data_file);
TRACE(1, "Based on option settings, binary cache " <<
(session.use_cache ? "WILL " : "will NOT ") << "be used");
if (! session.use_cache)
INFO("The binary cache mechanism will not be used");
// Read the command word and create a command object based on it
@ -134,7 +134,7 @@ static int read_and_report(report_t * report, int argc, char * argv[],
else if (verb == "parse") {
xml::xpath_t expr(*arg);
if (session.verbose_mode) {
IF_INFO() {
std::cout << "Value expression tree:" << std::endl;
expr.dump(std::cout);
std::cout << std::endl;
@ -231,7 +231,7 @@ static int read_and_report(report_t * report, int argc, char * argv[],
if (verb == "expr") {
xml::xpath_t expr(*arg);
if (session.verbose_mode) {
IF_INFO() {
*out << "Value expression tree:" << std::endl;
expr.dump(*out);
*out << std::endl;
@ -370,25 +370,46 @@ static int read_and_report(report_t * report, int argc, char * argv[],
return 0;
}
#ifdef DEBUG_ENABLED
extern int new_calls;
extern unsigned long new_size;
#endif
int main(int argc, char * argv[], char * envp[])
{
int status = 1;
#if defined(FULL_DEBUG)
ledger::verify_enabled = true;
#endif
for (int i = 1; i < argc; i++)
if (argv[i][0] == '-' && argv[i][1] == '-') {
#if defined(VERIFY_ON)
if (std::strcmp(argv[i], "--verify") == 0)
ledger::verify_enabled = true;
#endif
#if defined(DEBUG_ON)
if (i + 1 < argc && std::strcmp(argv[i], "--debug") == 0) {
ledger::_log_level = LOG_DEBUG;
ledger::_log_category = argv[i + 1];
i++;
}
#endif
#if defined(TRACING_ON)
if (i + 1 < argc && std::strcmp(argv[i], "--trace") == 0) {
ledger::_log_level = LOG_TRACE;
ledger::_trace_level = std::atoi(argv[i + 1]);
i++;
}
#endif
}
try {
std::ios::sync_with_stdio(false);
#if DEBUG_LEVEL < BETA
ledger::initialize();
#if ! defined(FULL_DEBUG)
ledger::do_cleanup = false;
#endif
TRACE(1, "Ledger starting");
ledger::amount_t::initialize();
std::auto_ptr<ledger::session_t> session(new ledger::session_t);
#if 0
@ -411,9 +432,6 @@ int main(int argc, char * argv[], char * envp[])
if (! ledger::do_cleanup) {
report.release();
session.release();
ledger::xml::xpath_t::lookahead.clear();
} else {
ledger::amount_t::shutdown();
}
}
#if 0
@ -446,11 +464,8 @@ int main(int argc, char * argv[], char * envp[])
status = _status;
}
IF_DEBUG_("ledger.trace.memory") {
report_memory(std::cerr);
std::cerr << "Total calls to new: " << new_calls << std::endl
<< "Total memory new'd: " << new_size << std::endl;
}
if (ledger::do_cleanup)
ledger::shutdown();
return status;
}

7
ofx.cc
View file

@ -76,12 +76,11 @@ int ofx_proc_transaction_cb(struct OfxTransactionData data,
if (data.unitprice_valid && data.unitprice != 1.0) {
std::ostringstream cstream;
stream << - data.unitprice;
xact->cost = new amount_t(stream.str() + " " + default_commodity->base_symbol());
stream << - data.unitprice << " " << default_commodity->base_symbol();
xact->cost = new amount_t(stream.str());
}
DEBUG_("ledger.ofx.parse", "xact " << xact->amount
<< " from " << *xact->account);
DEBUG_("ofx.parse", "xact " << xact->amount << " from " << *xact->account);
if (data.date_initiated_valid)
entry->_date = data.date_initiated;

View file

@ -127,10 +127,6 @@ static void scan_for_transactions(std::ostream& out, const xml::node_t * node)
void register_command::print_document(std::ostream& out,
xml::document_t * doc)
{
#if DEBUG_LEVEL >= BETA
unsigned long old_new_size = new_size;
#endif
#if 1
scan_for_transactions(out, doc->top);
out.flush();
@ -138,12 +134,6 @@ void register_command::print_document(std::ostream& out,
value_t nodelist;
xml::xpath_t::eval(nodelist, "//transaction", doc);
#if DEBUG_LEVEL >= BETA
std::cerr << "Memory requested preparing report: "
<< (new_size - old_new_size) << std::endl;
old_new_size = new_size;
#endif
const value_t::sequence_t * xact_list = nodelist.to_sequence();
assert(xact_list);
@ -170,12 +160,6 @@ void register_command::print_document(std::ostream& out,
<< xact->amount
<< std::endl;
}
#if DEBUG_LEVEL >= BETA
std::cerr << "Memory requested generating report: "
<< (new_size - old_new_size) << std::endl;
old_new_size = new_size;
#endif
#endif
}

View file

@ -62,13 +62,11 @@ journal_t * session_t::read_data(const string& master_account)
unsigned int entry_count = 0;
DEBUG_("ledger.cache",
"3. use_cache = " << use_cache);
DEBUG_("ledger.cache", "3. use_cache = " << use_cache);
if (use_cache && ! cache_file.empty() &&
! data_file.empty()) {
DEBUG_("ledger.cache",
"using_cache " << cache_file);
DEBUG_("ledger.cache", "using_cache " << cache_file);
cache_dirty = true;
if (access(cache_file.c_str(), R_OK) != -1) {
std::ifstream stream(cache_file.c_str());
@ -95,14 +93,12 @@ journal_t * session_t::read_data(const string& master_account)
if (read_journal(journal->price_db, journal)) {
throw_(exception, "Entries not allowed in price history file");
} else {
DEBUG_("ledger.cache",
"read price database " << journal->price_db);
DEBUG_("ledger.cache", "read price database " << journal->price_db);
journal->sources.pop_back();
}
}
DEBUG_("ledger.cache",
"rejected cache, parsing " << data_file);
DEBUG_("ledger.cache", "rejected cache, parsing " << data_file);
if (data_file == "-") {
use_cache = false;
journal->sources.push_back("<stdin>");
@ -171,14 +167,26 @@ xml::xpath_t::op_t * session_t::lookup(const string& name)
if (std::strncmp(p, "option_", 7) == 0) {
p = p + 7;
switch (*p) {
case 'd':
if (std::strcmp(p, "debug") == 0)
return MAKE_FUNCTOR(session_t, option_debug);
break;
case 'f':
if (! *(p + 1) || std::strcmp(p, "file") == 0)
return MAKE_FUNCTOR(session_t, option_file);
break;
case 't':
if (std::strcmp(p, "trace") == 0)
return MAKE_FUNCTOR(session_t, option_trace);
break;
case 'v':
if (std::strcmp(p, "verbose") == 0)
if (! *(p + 1) || std::strcmp(p, "verbose") == 0)
return MAKE_FUNCTOR(session_t, option_verbose);
else if (std::strcmp(p, "verify") == 0)
return MAKE_FUNCTOR(session_t, option_verify);
break;
}
}
@ -192,7 +200,11 @@ xml::xpath_t::op_t * session_t::lookup(const string& name)
// session_t object
void initialize()
{
IF_VERIFY()
initialize_memory_tracing();
amount_t::initialize();
xml::xpath_t::initialize();
}
void shutdown()
@ -200,7 +212,13 @@ void shutdown()
#if defined(USE_BOOST_PYTHON)
shutdown_for_python();
#endif
xml::xpath_t::shutdown();
amount_t::shutdown();
IF_VERIFY() {
TRACE(1, "Shutting down memory trace");
shutdown_memory_tracing();
}
}
} // namespace ledger

View file

@ -32,10 +32,6 @@ class session_t : public xml::xpath_t::scope_t
bool download_quotes;
bool use_cache;
bool cache_dirty;
bool debug_mode;
bool verbose_mode;
bool trace_alloc_mode;
bool trace_class_mode;
moment_t now;
@ -87,10 +83,6 @@ class session_t : public xml::xpath_t::scope_t
download_quotes(false),
use_cache(false),
cache_dirty(false),
debug_mode(false),
verbose_mode(false),
trace_alloc_mode(false),
trace_class_mode(false),
now(now),
@ -164,6 +156,18 @@ class session_t : public xml::xpath_t::scope_t
xml::xpath_t::scope_t * locals = NULL);
virtual xml::xpath_t::op_t * lookup(const string& name);
//
// Debug options
//
void option_verify(value_t&) {}
void option_trace(value_t&, xml::xpath_t::scope_t * locals) {}
void option_debug(value_t&, xml::xpath_t::scope_t * locals) {}
void option_verbose(value_t&) {
_log_level = LOG_INFO;
}
//
// Option handlers
//
@ -172,10 +176,6 @@ class session_t : public xml::xpath_t::scope_t
data_file = locals->args.to_string();
}
void option_verbose(value_t&) {
verbose_mode = true;
}
#if 0
#if defined(USE_BOOST_PYTHON)
void option_import(value_t&) {

View file

@ -1,3 +1,7 @@
import sys
sys.path.append("/home/johnw/src/ledger")
sys.path.append("/home/johnw/Products/ledger")
import unittest
import exceptions

View file

@ -53,10 +53,10 @@ parse_amount_expr(std::istream& in, journal_t *,
xml::xpath_t xpath(in, flags | XPATH_PARSE_RELAXED | XPATH_PARSE_PARTIAL);
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Parsed an amount expression");
"Parsed an amount expression");
#ifdef DEBUG_ENABLED
DEBUG_IF("ledger.textual.parse") {
#if 0
IF_DEBUG_("ledger.textual.parse") {
if (_debug_stream) {
xpath.dump(*_debug_stream);
*_debug_stream << std::endl;
@ -67,7 +67,7 @@ parse_amount_expr(std::istream& in, journal_t *,
amount = xpath.calc(static_cast<xml::transaction_node_t *>(xact.data)).to_amount();
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"The transaction amount is " << amount);
"The transaction amount is " << amount);
}
transaction_t * parse_transaction(char * line,
@ -125,12 +125,12 @@ transaction_t * parse_transaction(char * line,
case '*':
xact->state = transaction_t::CLEARED;
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Parsed the CLEARED flag");
"Parsed the CLEARED flag");
break;
case '!':
xact->state = transaction_t::PENDING;
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Parsed the PENDING flag");
"Parsed the PENDING flag");
break;
}
@ -142,18 +142,18 @@ transaction_t * parse_transaction(char * line,
(*b == '(' && *e == ')')) {
xact->flags |= TRANSACTION_VIRTUAL;
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Parsed a virtual account name");
"Parsed a virtual account name");
if (*b == '[') {
xact->flags |= TRANSACTION_BALANCE;
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Parsed a balanced virtual account name");
"Parsed a balanced virtual account name");
}
*account_path++ = '\0';
*e = '\0';
}
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Parsed account name " << account_path);
"Parsed account name " << account_path);
if (account_aliases.size() > 0) {
accounts_map::const_iterator i = account_aliases.find(account_path);
if (i != account_aliases.end())
@ -215,14 +215,14 @@ transaction_t * parse_transaction(char * line,
char c = peek_next_nonws(in);
if (c == '@') {
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Found a price indicator");
"Found a price indicator");
bool per_unit = true;
in.get(c);
if (in.peek() == '@') {
in.get(c);
per_unit = false;
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"And it's for a total price");
"And it's for a total price");
}
if (in.good() && ! in.eof()) {
@ -263,13 +263,13 @@ transaction_t * parse_transaction(char * line,
xact->entry->code);
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Total cost is " << *xact->cost);
"Total cost is " << *xact->cost);
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Per-unit cost is " << per_unit_cost);
"Per-unit cost is " << per_unit_cost);
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Annotated amount is " << xact->amount);
"Annotated amount is " << xact->amount);
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Bare amount is " << xact->amount.number());
"Bare amount is " << xact->amount.number());
}
}
}
@ -277,7 +277,7 @@ transaction_t * parse_transaction(char * line,
xact->amount.in_place_reduce();
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Reduced amount is " << xact->amount);
"Reduced amount is " << xact->amount);
}
// Parse the optional note
@ -285,7 +285,7 @@ transaction_t * parse_transaction(char * line,
if (note) {
xact->note = note;
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Parsed a note '" << xact->note << "'");
"Parsed a note '" << xact->note << "'");
if (char * b = std::strchr(xact->note.c_str(), '['))
if (char * e = std::strchr(xact->note.c_str(), ']')) {
@ -294,7 +294,7 @@ transaction_t * parse_transaction(char * line,
buf[e - b - 1] = '\0';
DEBUG_("ledger.textual.parse", "line " << linenum << ": " <<
"Parsed a transaction date " << buf);
"Parsed a transaction date " << buf);
if (char * p = std::strchr(buf, '=')) {
*p++ = '\0';
@ -840,7 +840,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
path = resolve_path(path);
DEBUG_("ledger.textual.include", "line " << linenum << ": " <<
"Including path '" << path << "'");
"Including path '" << path << "'");
include_stack.push_back(std::pair<string, int>
(journal->sources.back(), linenum - 1));

389
utils.cc
View file

@ -32,59 +32,68 @@ void debug_assert(const string& reason,
#if defined(VERIFY_ON)
namespace ledger {
#if defined(FULL_DEBUG)
bool verify_enabled = true;
bool verify_enabled = true;
#else
bool verify_enabled = false;
bool verify_enabled = false;
#endif
int new_calls = 0;
unsigned long new_size = 0;
typedef std::pair<std::string, std::size_t> allocation_pair;
typedef std::map<void *, allocation_pair> live_memory_map;
typedef std::pair<void *, allocation_pair> live_memory_pair;
typedef std::multimap<void *, allocation_pair> live_objects_map;
typedef std::pair<void *, allocation_pair> live_objects_pair;
typedef std::pair<unsigned int, std::size_t> count_size_pair;
typedef std::map<std::string, count_size_pair> object_count_map;
typedef std::pair<std::string, count_size_pair> object_count_pair;
static live_memory_map * live_memory = NULL;
static object_count_map * live_memory_count = NULL;
static object_count_map * total_memory_count = NULL;
static bool memory_tracing_active = false;
static live_objects_map * live_objects = NULL;
static object_count_map * live_object_count = NULL;
static object_count_map * total_object_count = NULL;
static object_count_map * total_ctor_count = NULL;
void initialize_memory_tracing()
{
memory_tracing_active = false;
live_memory = new live_memory_map;
live_memory_count = new object_count_map;
total_memory_count = new object_count_map;
live_objects = new live_objects_map;
live_object_count = new object_count_map;
total_object_count = new object_count_map;
total_ctor_count = new object_count_map;
memory_tracing_active = true;
}
void * operator new(std::size_t size) throw (std::bad_alloc) {
void * ptr = std::malloc(size);
ledger::new_calls++;
ledger::new_size += size;
return ptr;
}
void * operator new[](std::size_t size) throw (std::bad_alloc) {
void * ptr = std::malloc(size);
ledger::new_calls++;
ledger::new_size += size;
return ptr;
}
void * operator new(std::size_t size, const std::nothrow_t&) throw() {
void * ptr = std::malloc(size);
ledger::new_calls++;
ledger::new_size += size;
return ptr;
}
void * operator new[](std::size_t size, const std::nothrow_t&) throw() {
void * ptr = std::malloc(size);
ledger::new_calls++;
ledger::new_size += size;
return ptr;
}
void operator delete(void * ptr) throw() {
std::free(ptr);
}
void operator delete[](void * ptr) throw() {
std::free(ptr);
}
void operator delete(void * ptr, const std::nothrow_t&) throw() {
std::free(ptr);
}
void operator delete[](void * ptr, const std::nothrow_t&) throw() {
std::free(ptr);
}
void shutdown_memory_tracing()
{
memory_tracing_active = false;
namespace ledger {
IF_DEBUG_("memory.counts")
report_memory(std::cerr, true);
else
IF_DEBUG_("memory.counts.live")
report_memory(std::cerr);
live_objects_map live_objects;
object_count_map ctor_count;
object_count_map object_count;
object_count_map live_count;
delete live_memory; live_memory = NULL;
delete live_memory_count; live_memory_count = NULL;
delete total_memory_count; total_memory_count = NULL;
delete live_objects; live_objects = NULL;
delete live_object_count; live_object_count = NULL;
delete total_object_count; total_object_count = NULL;
delete total_ctor_count; total_ctor_count = NULL;
}
inline void add_to_count_map(object_count_map& the_map,
const char * name, std::size_t size)
@ -96,10 +105,117 @@ inline void add_to_count_map(object_count_map& the_map,
} else {
std::pair<object_count_map::iterator, bool> result =
the_map.insert(object_count_pair(name, count_size_pair(1, size)));
assert(result.second);
VERIFY(result.second);
}
}
std::size_t current_memory_size()
{
std::size_t memory_size = 0;
for (object_count_map::const_iterator i = live_memory_count->begin();
i != live_memory_count->end();
i++)
memory_size += (*i).second.second;
return memory_size;
}
static void trace_new_func(void * ptr, const char * which, std::size_t size)
{
memory_tracing_active = false;
if (! live_memory) return;
live_memory->insert(live_memory_pair(ptr, allocation_pair(which, size)));
add_to_count_map(*live_memory_count, which, size);
add_to_count_map(*total_memory_count, which, size);
add_to_count_map(*total_memory_count, "__ALL__", size);
memory_tracing_active = true;
}
static void trace_delete_func(void * ptr, const char * which)
{
memory_tracing_active = false;
if (! live_memory) return;
// Ignore deletions of memory not tracked, since it's possible that
// a user (like boost) allocated a block of memory before memory
// tracking began, and then deleted it before memory tracking ended.
// If it really is a double-delete, the malloc library on OS/X will
// notify me.
live_memory_map::iterator i = live_memory->find(ptr);
if (i == live_memory->end())
return;
std::size_t size = (*i).second.second;
VERIFY((*i).second.first == which);
live_memory->erase(i);
object_count_map::iterator j = live_memory_count->find(which);
VERIFY(j != live_memory_count->end());
(*j).second.second -= size;
if (--(*j).second.first == 0)
live_memory_count->erase(j);
memory_tracing_active = true;
}
} // namespace ledger
void * operator new(std::size_t size) throw (std::bad_alloc) {
void * ptr = std::malloc(size);
if (DO_VERIFY() && ledger::memory_tracing_active)
ledger::trace_new_func(ptr, "new", size);
return ptr;
}
void * operator new(std::size_t size, const std::nothrow_t&) throw() {
void * ptr = std::malloc(size);
if (DO_VERIFY() && ledger::memory_tracing_active)
ledger::trace_new_func(ptr, "new", size);
return ptr;
}
void * operator new[](std::size_t size) throw (std::bad_alloc) {
void * ptr = std::malloc(size);
if (DO_VERIFY() && ledger::memory_tracing_active)
ledger::trace_new_func(ptr, "new[]", size);
return ptr;
}
void * operator new[](std::size_t size, const std::nothrow_t&) throw() {
void * ptr = std::malloc(size);
if (DO_VERIFY() && ledger::memory_tracing_active)
ledger::trace_new_func(ptr, "new[]", size);
return ptr;
}
void operator delete(void * ptr) throw() {
if (DO_VERIFY() && ledger::memory_tracing_active)
ledger::trace_delete_func(ptr, "new");
std::free(ptr);
}
void operator delete(void * ptr, const std::nothrow_t&) throw() {
if (DO_VERIFY() && ledger::memory_tracing_active)
ledger::trace_delete_func(ptr, "new");
std::free(ptr);
}
void operator delete[](void * ptr) throw() {
if (DO_VERIFY() && ledger::memory_tracing_active)
ledger::trace_delete_func(ptr, "new[]");
std::free(ptr);
}
void operator delete[](void * ptr, const std::nothrow_t&) throw() {
if (DO_VERIFY() && ledger::memory_tracing_active)
ledger::trace_delete_func(ptr, "new[]");
std::free(ptr);
}
namespace ledger {
inline void report_count_map(std::ostream& out, object_count_map& the_map)
{
for (object_count_map::iterator i = the_map.begin();
@ -111,88 +227,127 @@ inline void report_count_map(std::ostream& out, object_count_map& the_map)
<< std::endl;
}
bool trace_ctor_func(void * ptr, const char * cls_name, const char * args,
std::size_t current_objects_size()
{
std::size_t objects_size = 0;
for (object_count_map::const_iterator i = live_object_count->begin();
i != live_object_count->end();
i++)
objects_size += (*i).second.second;
return objects_size;
}
void trace_ctor_func(void * ptr, const char * cls_name, const char * args,
std::size_t cls_size)
{
memory_tracing_active = false;
if (! live_objects) return;
static char name[1024];
std::strcpy(name, cls_name);
std::strcat(name, "(");
std::strcat(name, args);
std::strcat(name, ")");
DEBUG_("ledger.trace.debug", "TRACE_CTOR " << ptr << " " << name);
DEBUG_("verify.memory", "TRACE_CTOR " << ptr << " " << name);
live_objects.insert(live_objects_pair(ptr, cls_name));
live_objects->insert(live_objects_pair(ptr, allocation_pair(cls_name, cls_size)));
add_to_count_map(ctor_count, name, cls_size);
add_to_count_map(object_count, cls_name, cls_size);
add_to_count_map(object_count, "__ALL__", cls_size);
add_to_count_map(live_count, cls_name, cls_size);
add_to_count_map(*live_object_count, cls_name, cls_size);
add_to_count_map(*total_object_count, cls_name, cls_size);
add_to_count_map(*total_object_count, "__ALL__", cls_size);
add_to_count_map(*total_ctor_count, name, cls_size);
return true;
memory_tracing_active = true;
}
bool trace_dtor_func(void * ptr, const char * cls_name, std::size_t cls_size)
void trace_dtor_func(void * ptr, const char * cls_name, std::size_t cls_size)
{
memory_tracing_active = false;
if (! live_objects) return;
DEBUG_("ledger.trace.debug", "TRACE_DTOR " << ptr << " " << cls_name);
live_objects_map::iterator i = live_objects.find(ptr);
if (i == live_objects.end()) {
std::cerr << "Destruction of unknown object of type " << cls_name
<< " " << ptr << std::endl;
assert(0);
return false;
}
live_objects_map::iterator i = live_objects->find(ptr);
VERIFY(i != live_objects->end());
int ptr_count = live_objects.count(ptr);
int ptr_count = live_objects->count(ptr);
for (int x = 0; x < ptr_count; x++, i++) {
if ((*i).second == cls_name) {
live_objects.erase(i);
if ((*i).second.first == cls_name) {
live_objects->erase(i);
break;
}
}
object_count_map::iterator k = live_count.find(cls_name);
if (k == live_count.end()) {
std::cerr << "Destruction of unregistered class " << cls_name
<< std::endl;;
assert(0);
return false;
}
object_count_map::iterator k = live_object_count->find(cls_name);
VERIFY(k != live_object_count->end());
(*k).second.second -= cls_size;
if (--(*k).second.first == 0)
live_count.erase(k);
live_object_count->erase(k);
return true;
memory_tracing_active = true;
}
void report_memory(std::ostream& out)
void report_memory(std::ostream& out, bool report_all)
{
if (live_count.size() > 0) {
out << "Live object counts:" << std::endl;
report_count_map(out, live_count);
if (! live_memory) return;
if (live_memory_count->size() > 0) {
out << "NOTE: There may be memory held by Boost "
<< "and libstdc++ after ledger::shutdown()" << std::endl;
out << "Live memory count:" << std::endl;
report_count_map(out, *live_memory_count);
}
if (live_objects.size() > 0) {
out << "Live objects:" << std::endl;
if (live_memory->size() > 0) {
out << "Live memory:" << std::endl;
for (live_objects_map::iterator i = live_objects.begin();
i != live_objects.end();
for (live_memory_map::const_iterator i = live_memory->begin();
i != live_memory->end();
i++)
out << " " << std::right << std::setw(7) << (*i).first
<< " " << std::left << (*i).second
<< " " << std::right << std::setw(7) << (*i).second.second
<< " " << std::left << (*i).second.first
<< std::endl;
}
if (object_count.size() > 0) {
out << "Object counts:" << std::endl;
report_count_map(out, object_count);
if (report_all && total_memory_count->size() > 0) {
out << "Total memory counts:" << std::endl;
report_count_map(out, *total_memory_count);
}
if (ctor_count.size() > 0) {
out << "Constructor counts:" << std::endl;
report_count_map(out, ctor_count);
if (live_object_count->size() > 0) {
out << "Live object count:" << std::endl;
report_count_map(out, *live_object_count);
}
if (live_objects->size() > 0) {
out << "Live objects:" << std::endl;
for (live_objects_map::const_iterator i = live_objects->begin();
i != live_objects->end();
i++)
out << " " << std::right << std::setw(7) << (*i).first
<< " " << std::right << std::setw(7) << (*i).second.second
<< " " << std::left << (*i).second.first
<< std::endl;
}
if (report_all) {
if (total_object_count->size() > 0) {
out << "Total object counts:" << std::endl;
report_count_map(out, *total_object_count);
}
if (total_ctor_count->size() > 0) {
out << "Total constructor counts:" << std::endl;
report_count_map(out, *total_ctor_count);
}
}
}
@ -255,8 +410,64 @@ std::string _log_category;
std::ostream * _log_stream = &std::cerr;
std::ostringstream _log_buffer;
static inline void stream_memory_size(std::ostream& out, std::size_t size)
{
if (size < 1024)
out << size << 'b';
else if (size < (1024 * 1024))
out << (double(size) / 1024.0) << 'K';
else if (size < (1024 * 1024 * 1024))
out << (double(size) / (1024.0 * 1024.0)) << 'M';
else if (size < (1024 * 1024 * 1024 * 1024))
out << (double(size) / (1024.0 * 1024.0 * 1024.0)) << 'G';
else
assert(false);
}
static bool logger_has_run = false;
bool logger_func(log_level_t level)
{
if (! logger_has_run) {
logger_has_run = true;
IF_VERIFY()
*_log_stream << " TIME OBJSZ MEMSZ LEVEL MESSAGE" << std::endl;
else
*_log_stream << " TIME LEVEL MESSAGE" << std::endl;
}
*_log_stream << std::right << std::setw(6)
<< (double(std::clock()) / double(CLOCKS_PER_SEC));
IF_VERIFY() {
*_log_stream << std::right << std::setw(6) << std::setprecision(3);
stream_memory_size(*_log_stream, current_objects_size());
*_log_stream << std::right << std::setw(6) << std::setprecision(3);
stream_memory_size(*_log_stream, current_memory_size());
}
*_log_stream << " " << std::left << std::setw(7);
switch (level) {
case LOG_CRIT: *_log_stream << "[CRIT]"; break;
case LOG_FATAL: *_log_stream << "[FATAL]"; break;
case LOG_ASSERT: *_log_stream << "[ASSRT]"; break;
case LOG_ERROR: *_log_stream << "[ERROR]"; break;
case LOG_VERIFY: *_log_stream << "[VERFY]"; break;
case LOG_WARN: *_log_stream << "[WARN]"; break;
case LOG_INFO: *_log_stream << "[INFO]"; break;
case LOG_EXCEPT: *_log_stream << "[EXCPT]"; break;
case LOG_DEBUG: *_log_stream << "[DEBUG]"; break;
case LOG_TRACE: *_log_stream << "[TRACE]"; break;
case LOG_OFF:
case LOG_ALL:
assert(false);
break;
}
*_log_stream << ' ' << _log_buffer.str() << std::endl;
_log_buffer.str("");
}

87
utils.h
View file

@ -73,32 +73,26 @@ namespace ledger {
extern bool verify_enabled;
#define VERIFY(x) (verify_enabled ? assert(x) : ((void)0))
#define VERIFY(x) (ledger::verify_enabled ? assert(x) : ((void)0))
#define DO_VERIFY() ledger::verify_enabled
#define IF_VERIFY() if (DO_VERIFY())
extern int new_calls;
extern unsigned long new_size;
void initialize_memory_tracing();
void shutdown_memory_tracing();
typedef std::multimap<void *, std::string> live_objects_map;
typedef std::pair<void *, std::string> live_objects_pair;
typedef std::pair<unsigned int, std::size_t> count_size_pair;
typedef std::map<std::string, count_size_pair> object_count_map;
typedef std::pair<std::string, count_size_pair> object_count_pair;
std::size_t current_memory_size();
std::size_t current_objects_size();
extern live_objects_map live_objects;
extern object_count_map live_count;
extern object_count_map ctor_count;
extern object_count_map object_count;
bool trace_ctor_func(void * ptr, const char * cls_name, const char * args,
void trace_ctor_func(void * ptr, const char * cls_name, const char * args,
std::size_t cls_size);
bool trace_dtor_func(void * ptr, const char * cls_name, std::size_t cls_size);
void trace_dtor_func(void * ptr, const char * cls_name, std::size_t cls_size);
#define TRACE_CTOR(cls, args) \
VERIFY(trace_ctor_func(this, #cls, args, sizeof(cls)))
(DO_VERIFY() ? trace_ctor_func(this, #cls, args, sizeof(cls)) : ((void)0))
#define TRACE_DTOR(cls) \
VERIFY(trace_dtor_func(this, #cls, sizeof(cls)))
(DO_VERIFY() ? trace_dtor_func(this, #cls, sizeof(cls)) : ((void)0))
void report_memory(std::ostream& out);
void report_memory(std::ostream& out, bool report_all = false);
#if ! defined(USE_BOOST_PYTHON)
@ -213,20 +207,21 @@ bool logger_func(log_level_t level);
static const char * const _this_category = cat
#define SHOW_TRACE(lvl) \
(_log_level >= LOG_TRACE && lvl >= _trace_level)
(_log_level >= LOG_TRACE && lvl <= _trace_level)
#define SHOW_DEBUG_(cat) \
(_log_level >= LOG_DEBUG && \
(_log_category == cat || \
_log_category.find(string(cat) + ".") == 0))
inline bool category_matches(const char * cat) {
return (_log_category == cat ||
(std::strlen(cat) > _log_category.size() + 1 &&
std::strncmp(cat, _log_category.c_str(),
_log_category.size()) == 0 &&
cat[_log_category.size()] == '.'));
}
#define SHOW_DEBUG_(cat) \
(_log_level >= LOG_DEBUG && category_matches(cat))
#define SHOW_DEBUG() SHOW_DEBUG_(_this_category)
#define SHOW_INFO_(cat) \
(_log_level >= LOG_INFO && \
(_log_category == cat || \
_log_category.find(string(cat) + ".") == 0))
#define SHOW_INFO() SHOW_INFO_(_this_category)
#define SHOW_INFO() (_log_level >= LOG_INFO)
#define SHOW_WARN() (_log_level >= LOG_WARN)
#define SHOW_ERROR() (_log_level >= LOG_ERROR)
#define SHOW_FATAL() (_log_level >= LOG_FATAL)
@ -248,14 +243,11 @@ bool logger_func(log_level_t level);
#define DEBUG(msg)
#endif
#define INFO_(cat, msg) \
(SHOW_INFO(cat) ? ((_log_buffer << msg), logger_func(LOG_INFO)) : false)
#define INFO(msg) INFO_(_this_category, msg)
#define LOG_MACRO(level, msg) \
(_log_level >= level ? \
((_log_buffer << msg), logger_func(level)) : false)
#define INFO(msg) LOG_MACRO(LOG_INFO, msg)
#define WARN(msg) LOG_MACRO(LOG_WARN, msg)
#define ERROR(msg) LOG_MACRO(LOG_ERROR, msg)
#define FATAL(msg) LOG_MACRO(LOG_FATAL, msg)
@ -271,7 +263,6 @@ bool logger_func(log_level_t level);
#define SHOW_TRACE(lvl) false
#define SHOW_DEBUG_(cat) false
#define SHOW_DEBUG() false
#define SHOW_INFO_(cat) false
#define SHOW_INFO() false
#define SHOW_WARN() false
#define SHOW_ERROR() false
@ -282,7 +273,6 @@ bool logger_func(log_level_t level);
#define DEBUG(msg)
#define DEBUG_(cat, msg)
#define INFO(msg)
#define INFO_(cat, msg)
#define WARN(msg)
#define ERROR(msg)
#define FATAL(msg)
@ -293,7 +283,6 @@ bool logger_func(log_level_t level);
#define IF_TRACE(lvl) if (SHOW_TRACE(lvl))
#define IF_DEBUG_(cat) if (SHOW_DEBUG_(cat))
#define IF_DEBUG() if (SHOW_DEBUG())
#define IF_INFO_(cat) if (SHOW_INFO_(cat))
#define IF_INFO() if (SHOW_INFO())
#define IF_WARN() if (SHOW_WARN())
#define IF_ERROR() if (SHOW_ERROR())
@ -354,18 +343,12 @@ void finish_timer(const char * name);
#define DEBUG_FINISH(name)
#endif
#define info_start_(name, cat, msg) \
(info_(cat, msg) && start_timer(#name))
#define info_start(name, msg) \
info_start_(name, _this_category, msg)
#define info_stop_(name, cat) \
(show_info_(cat) ? stop_timer(#name) : ((void)0))
#define info_stop(name) \
info_stop_(name, _this_category)
#define info_finish_(name, cat) \
(show_info_(cat) ? finish_timer(#name) : ((void)0))
#define info_finish(name) \
info_finish_(name, _this_category)
#define INFO_START(name, msg) \
(INFO(msg) && start_timer(#name))
#define INFO_STOP(name) \
(SHOW_INFO() ? stop_timer(#name) : ((void)0))
#define INFO_FINISH(name) \
(SHOW_INFO() ? finish_timer(#name) : ((void)0))
} // namespace ledger
@ -380,10 +363,10 @@ void finish_timer(const char * name);
#define DEBUG_STOP(name)
#define DEBUG_FINISH(name)
#define info_start(name, msg)
#define info_start_(name, cat, msg)
#define info_stop(name)
#define info_finish(name)
#define INFO_START(name, msg)
#define INFO_START_(name, cat, msg)
#define INFO_STOP(name)
#define INFO_FINISH(name)
#endif // TIMERS_ON

View file

@ -10,9 +10,20 @@ namespace ledger {
namespace xml {
#ifndef THREADSAFE
xpath_t::token_t xpath_t::lookahead;
xpath_t::token_t * xpath_t::lookahead = NULL;
#endif
void xpath_t::initialize()
{
lookahead = new xpath_t::token_t;
}
void xpath_t::shutdown()
{
delete lookahead;
lookahead = NULL;
}
void xpath_t::token_t::parse_ident(std::istream& in)
{
if (in.eof()) {
@ -1130,9 +1141,17 @@ xpath_t::parse_expr(std::istream& in, unsigned short tflags) const
if (use_lookahead) {
use_lookahead = false;
#ifdef THREADSAFE
lookahead.rewind(in);
#else
lookahead->rewind(in);
#endif
}
#ifdef THREADSAFE
lookahead.clear();
#else
lookahead->clear();
#endif
return node.release();
}

27
xpath.h
View file

@ -11,6 +11,9 @@ class xpath_t
public:
struct op_t;
static void initialize();
static void shutdown();
DECLARE_EXCEPTION(parse_exception);
DECLARE_EXCEPTION(compile_exception);
DECLARE_EXCEPTION(calc_exception);
@ -422,21 +425,21 @@ public:
void release() const {
DEBUG_("ledger.xpath.memory",
"Releasing " << this << ", refc now " << refc - 1);
"Releasing " << this << ", refc now " << refc - 1);
assert(refc > 0);
if (--refc == 0)
delete this;
}
op_t * acquire() {
DEBUG_("ledger.xpath.memory",
"Acquiring " << this << ", refc now " << refc + 1);
"Acquiring " << this << ", refc now " << refc + 1);
assert(refc >= 0);
refc++;
return this;
}
const op_t * acquire() const {
DEBUG_("ledger.xpath.memory",
"Acquiring " << this << ", refc now " << refc + 1);
"Acquiring " << this << ", refc now " << refc + 1);
assert(refc >= 0);
refc++;
return this;
@ -521,21 +524,33 @@ public:
}
#ifdef THREADSAFE
mutable token_t lookahead;
mutable token_t lookahead;
#else
static token_t lookahead;
static token_t * lookahead;
#endif
mutable bool use_lookahead;
mutable bool use_lookahead;
token_t& next_token(std::istream& in, unsigned short tflags) const {
if (use_lookahead)
use_lookahead = false;
else
#ifdef THREADSAFE
lookahead.next(in, tflags);
#else
lookahead->next(in, tflags);
#endif
#ifdef THREADSAFE
return lookahead;
#else
return *lookahead;
#endif
}
void push_token(const token_t& tok) const {
#ifdef THREADSAFE
assert(&tok == &lookahead);
#else
assert(&tok == lookahead);
#endif
use_lookahead = true;
}
void push_token() const {