add copy-on-write semantics to amount.cc; cuts object creation by 5x
This commit is contained in:
parent
06ac87ab20
commit
fb91d6f21e
6 changed files with 238 additions and 132 deletions
296
amount.cc
296
amount.cc
|
|
@ -1,18 +1,64 @@
|
|||
#include "ledger.h"
|
||||
#include "binary.h"
|
||||
#include "error.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "gmp.h"
|
||||
#include <deque>
|
||||
|
||||
#define MPZ(x) ((MP_INT *)(x))
|
||||
#include "gmp.h"
|
||||
|
||||
namespace ledger {
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
static int ctors = 0;
|
||||
static int dtors = 0;
|
||||
#endif
|
||||
|
||||
struct amount_t::bigint_t {
|
||||
mpz_t val;
|
||||
unsigned int ref;
|
||||
unsigned int index;
|
||||
|
||||
bigint_t() : ref(1), index(0) {
|
||||
mpz_init(val);
|
||||
#ifdef DEBUG_ENABLED
|
||||
ctors++;
|
||||
#endif
|
||||
}
|
||||
bigint_t(mpz_t _val) : ref(1), index(0) {
|
||||
mpz_init_set(val, _val);
|
||||
#ifdef DEBUG_ENABLED
|
||||
ctors++;
|
||||
#endif
|
||||
}
|
||||
~bigint_t() {
|
||||
assert(ref == 0);
|
||||
mpz_clear(val);
|
||||
#ifdef DEBUG_ENABLED
|
||||
dtors++;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
static struct ctor_dtor_info {
|
||||
~ctor_dtor_info() {
|
||||
DEBUG_CLASS("ledger.amount.bigint");
|
||||
DEBUG_PRINT_("bigint_t ctor count = " << ctors);
|
||||
DEBUG_PRINT_("bigint_t dtor count = " << dtors);
|
||||
}
|
||||
} __info;
|
||||
#endif
|
||||
|
||||
#define MPZ(x) ((x)->val)
|
||||
|
||||
static mpz_t temp;
|
||||
static mpz_t divisor;
|
||||
static mpz_t true_value;
|
||||
|
||||
static struct init_amounts {
|
||||
init_amounts() {
|
||||
mpz_init(temp);
|
||||
mpz_init(divisor);
|
||||
mpz_init(true_value);
|
||||
mpz_set_ui(true_value, 1);
|
||||
|
|
@ -21,6 +67,7 @@ static struct init_amounts {
|
|||
~init_amounts() {
|
||||
mpz_clear(true_value);
|
||||
mpz_clear(divisor);
|
||||
mpz_clear(temp);
|
||||
}
|
||||
#endif
|
||||
} initializer;
|
||||
|
|
@ -80,73 +127,91 @@ static void mpz_round(mpz_t out, mpz_t value, int value_prec, int round_prec)
|
|||
}
|
||||
|
||||
amount_t::amount_t(const bool value)
|
||||
: quantity(NULL), commodity(NULL)
|
||||
{
|
||||
if (value) {
|
||||
commodity = commodity_t::null_commodity;
|
||||
quantity = new bigint_t(true_value);
|
||||
precision = 0;
|
||||
quantity = new MP_INT;
|
||||
mpz_init_set(MPZ(quantity), true_value);
|
||||
commodity = commodity_t::null_commodity;
|
||||
} else {
|
||||
quantity = NULL;
|
||||
precision = 0;
|
||||
commodity = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
amount_t::amount_t(const int value)
|
||||
: quantity(NULL), commodity(NULL)
|
||||
{
|
||||
if (value != 0) {
|
||||
_init();
|
||||
commodity = commodity_t::null_commodity;
|
||||
precision = 0;
|
||||
mpz_set_si(MPZ(quantity), value);
|
||||
precision = 0;
|
||||
commodity = commodity_t::null_commodity;
|
||||
} else {
|
||||
quantity = NULL;
|
||||
precision = 0;
|
||||
commodity = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
amount_t::amount_t(const unsigned int value)
|
||||
: quantity(NULL), commodity(NULL)
|
||||
{
|
||||
if (value != 0) {
|
||||
_init();
|
||||
commodity = commodity_t::null_commodity;
|
||||
precision = 0;
|
||||
mpz_set_ui(MPZ(quantity), value);
|
||||
precision = 0;
|
||||
commodity = commodity_t::null_commodity;
|
||||
} else {
|
||||
quantity = NULL;
|
||||
precision = 0;
|
||||
commodity = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
amount_t::amount_t(const double value)
|
||||
: quantity(NULL), commodity(NULL)
|
||||
{
|
||||
if (value != 0.0) {
|
||||
_init();
|
||||
commodity = commodity_t::null_commodity;
|
||||
// jww (2004-08-20): How do I calculate?
|
||||
precision = 0;
|
||||
mpz_set_d(MPZ(quantity), value);
|
||||
// jww (2004-08-20): How do I calculate this?
|
||||
precision = 0;
|
||||
commodity = commodity_t::null_commodity;
|
||||
} else {
|
||||
quantity = NULL;
|
||||
precision = 0;
|
||||
commodity = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void amount_t::_clear()
|
||||
void amount_t::_release()
|
||||
{
|
||||
mpz_clear(MPZ(quantity));
|
||||
delete (MP_INT *) quantity;
|
||||
if (--quantity->ref == 0)
|
||||
delete quantity;
|
||||
}
|
||||
|
||||
void amount_t::_init()
|
||||
{
|
||||
quantity = new MP_INT;
|
||||
mpz_init(MPZ(quantity));
|
||||
quantity = new bigint_t;
|
||||
}
|
||||
|
||||
void amount_t::_dup()
|
||||
{
|
||||
if (quantity->ref > 1) {
|
||||
bigint_t * q = new bigint_t(MPZ(quantity));
|
||||
_release();
|
||||
quantity = q;
|
||||
}
|
||||
}
|
||||
|
||||
void amount_t::_copy(const amount_t& amt)
|
||||
{
|
||||
if (quantity) {
|
||||
mpz_set(MPZ(quantity), MPZ(amt.quantity));
|
||||
} else {
|
||||
quantity = new MP_INT;
|
||||
mpz_init_set(MPZ(quantity), MPZ(amt.quantity));
|
||||
}
|
||||
if (quantity)
|
||||
_release();
|
||||
|
||||
quantity = amt.quantity;
|
||||
quantity->ref++;
|
||||
|
||||
commodity = amt.commodity;
|
||||
precision = amt.precision;
|
||||
assert(commodity);
|
||||
}
|
||||
|
||||
amount_t& amount_t::operator=(const std::string& value)
|
||||
|
|
@ -167,29 +232,30 @@ amount_t& amount_t::operator=(const char * value)
|
|||
// assignment operator
|
||||
amount_t& amount_t::operator=(const amount_t& amt)
|
||||
{
|
||||
if (amt.quantity) {
|
||||
if (amt.quantity)
|
||||
_copy(amt);
|
||||
} else {
|
||||
commodity = amt.commodity;
|
||||
precision = amt.precision;
|
||||
}
|
||||
else if (quantity)
|
||||
_clear();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
amount_t& amount_t::operator=(const bool value)
|
||||
{
|
||||
if (! value) {
|
||||
if (quantity) {
|
||||
if (quantity)
|
||||
_clear();
|
||||
quantity = NULL;
|
||||
commodity = NULL;
|
||||
precision = 0;
|
||||
}
|
||||
} else {
|
||||
commodity = commodity_t::null_commodity;
|
||||
precision = 0;
|
||||
quantity = new MP_INT;
|
||||
mpz_init_set(MPZ(quantity), true_value);
|
||||
if (! quantity) {
|
||||
_init();
|
||||
}
|
||||
else if (quantity->ref > 1) {
|
||||
_release();
|
||||
_init();
|
||||
}
|
||||
mpz_set(MPZ(quantity), true_value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -197,15 +263,18 @@ amount_t& amount_t::operator=(const bool value)
|
|||
amount_t& amount_t::operator=(const int value)
|
||||
{
|
||||
if (value == 0) {
|
||||
if (quantity) {
|
||||
if (quantity)
|
||||
_clear();
|
||||
quantity = NULL;
|
||||
commodity = NULL;
|
||||
precision = 0;
|
||||
}
|
||||
} else {
|
||||
commodity = commodity_t::null_commodity;
|
||||
precision = 0;
|
||||
if (! quantity) {
|
||||
_init();
|
||||
}
|
||||
else if (quantity->ref > 1) {
|
||||
_release();
|
||||
_init();
|
||||
}
|
||||
mpz_set_si(MPZ(quantity), value);
|
||||
}
|
||||
return *this;
|
||||
|
|
@ -214,15 +283,18 @@ amount_t& amount_t::operator=(const int value)
|
|||
amount_t& amount_t::operator=(const unsigned int value)
|
||||
{
|
||||
if (value == 0) {
|
||||
if (quantity) {
|
||||
if (quantity)
|
||||
_clear();
|
||||
quantity = NULL;
|
||||
commodity = NULL;
|
||||
precision = 0;
|
||||
}
|
||||
} else {
|
||||
commodity = commodity_t::null_commodity;
|
||||
precision = 0;
|
||||
if (! quantity) {
|
||||
_init();
|
||||
}
|
||||
else if (quantity->ref > 1) {
|
||||
_release();
|
||||
_init();
|
||||
}
|
||||
mpz_set_ui(MPZ(quantity), value);
|
||||
}
|
||||
return *this;
|
||||
|
|
@ -231,16 +303,19 @@ amount_t& amount_t::operator=(const unsigned int value)
|
|||
amount_t& amount_t::operator=(const double value)
|
||||
{
|
||||
if (value == 0.0) {
|
||||
if (quantity) {
|
||||
if (quantity)
|
||||
_clear();
|
||||
quantity = NULL;
|
||||
commodity = NULL;
|
||||
precision = 0;
|
||||
}
|
||||
} else {
|
||||
commodity = commodity_t::null_commodity;
|
||||
// jww (2004-08-20): How do I calculate?
|
||||
precision = 0;
|
||||
if (! quantity) {
|
||||
_init();
|
||||
}
|
||||
else if (quantity->ref > 1) {
|
||||
_release();
|
||||
_init();
|
||||
}
|
||||
mpz_set_d(MPZ(quantity), value);
|
||||
}
|
||||
return *this;
|
||||
|
|
@ -252,6 +327,8 @@ void amount_t::_resize(int prec)
|
|||
if (prec == precision)
|
||||
return;
|
||||
|
||||
_dup();
|
||||
|
||||
if (prec < precision) {
|
||||
mpz_ui_pow_ui(divisor, 10, precision - prec);
|
||||
mpz_tdiv_q(MPZ(quantity), MPZ(quantity), divisor);
|
||||
|
|
@ -272,6 +349,8 @@ amount_t& amount_t::operator OP(const amount_t& amt) \
|
|||
_init(); \
|
||||
commodity = amt.commodity; \
|
||||
precision = amt.precision; \
|
||||
} else { \
|
||||
_dup(); \
|
||||
} \
|
||||
\
|
||||
if (commodity != amt.commodity) \
|
||||
|
|
@ -298,8 +377,10 @@ DEF_OPERATOR(-=, mpz_sub)
|
|||
// unary negation
|
||||
amount_t& amount_t::negate()
|
||||
{
|
||||
if (quantity)
|
||||
if (quantity) {
|
||||
_dup();
|
||||
mpz_ui_sub(MPZ(quantity), 0, MPZ(quantity));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -454,12 +535,10 @@ amount_t::operator bool() const
|
|||
return mpz_sgn(MPZ(quantity)) != 0;
|
||||
} else {
|
||||
assert(commodity);
|
||||
mpz_t temp;
|
||||
mpz_init_set(temp, MPZ(quantity));
|
||||
mpz_set(temp, MPZ(quantity));
|
||||
mpz_ui_pow_ui(divisor, 10, precision - commodity->precision);
|
||||
mpz_tdiv_q(temp, temp, divisor);
|
||||
bool zero = mpz_sgn(temp) == 0;
|
||||
mpz_clear(temp);
|
||||
return ! zero;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -481,6 +560,8 @@ amount_t& amount_t::operator*=(const amount_t& amt)
|
|||
if (! amt.quantity || ! quantity)
|
||||
return *this;
|
||||
|
||||
_dup();
|
||||
|
||||
mpz_mul(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity));
|
||||
precision += amt.precision;
|
||||
|
||||
|
|
@ -495,6 +576,8 @@ amount_t& amount_t::operator/=(const amount_t& amt)
|
|||
if (! amt.quantity)
|
||||
throw amount_error("Divide by zero");
|
||||
|
||||
_dup();
|
||||
|
||||
// Increase the value's precision, to capture fractional parts after
|
||||
// the divide.
|
||||
mpz_ui_pow_ui(divisor, 10, amt.precision + 6);
|
||||
|
|
@ -514,6 +597,7 @@ amount_t amount_t::round(int prec) const
|
|||
return *this;
|
||||
} else {
|
||||
amount_t temp = *this;
|
||||
temp._dup();
|
||||
mpz_round(MPZ(temp.quantity), MPZ(temp.quantity),
|
||||
precision, prec == -1 ? commodity->precision : prec);
|
||||
return temp;
|
||||
|
|
@ -591,9 +675,6 @@ std::ostream& operator<<(std::ostream& out, const amount_t& amt)
|
|||
std::list<std::string> strs;
|
||||
char buf[4];
|
||||
|
||||
mpz_t temp;
|
||||
mpz_init(temp);
|
||||
|
||||
for (int powers = 0; true; powers += 3) {
|
||||
if (powers > 0) {
|
||||
mpz_ui_pow_ui(divisor, 10, powers);
|
||||
|
|
@ -622,8 +703,6 @@ std::ostream& operator<<(std::ostream& out, const amount_t& amt)
|
|||
|
||||
printed = true;
|
||||
}
|
||||
|
||||
mpz_clear(temp);
|
||||
}
|
||||
|
||||
if (amt.commodity->precision) {
|
||||
|
|
@ -696,8 +775,9 @@ void amount_t::parse(std::istream& in)
|
|||
std::string quant;
|
||||
unsigned int flags = COMMODITY_STYLE_DEFAULTS;;
|
||||
|
||||
if (! quantity)
|
||||
_init();
|
||||
if (quantity)
|
||||
_release();
|
||||
_init();
|
||||
|
||||
char c = peek_next_nonws(in);
|
||||
if (std::isdigit(c) || c == '.' || c == '-') {
|
||||
|
|
@ -771,64 +851,80 @@ void amount_t::parse(std::istream& in)
|
|||
delete[] buf;
|
||||
}
|
||||
|
||||
// If necessary, amounts may be recorded in a binary file textually.
|
||||
// This offers little advantage, and requires binary<->decimal
|
||||
// conversion each time the file is saved or loaded.
|
||||
//
|
||||
//#define WRITE_AMOUNTS_TEXTUALLY
|
||||
|
||||
static char buf[4096];
|
||||
static int index = 0;
|
||||
|
||||
void amount_t::write_quantity(std::ostream& out) const
|
||||
{
|
||||
unsigned short len;
|
||||
if (quantity) {
|
||||
#ifdef WRITE_AMOUNTS_TEXTUALLY
|
||||
mpz_get_str(buf, 10, MPZ(quantity));
|
||||
len = std::strlen(buf);
|
||||
#else
|
||||
char byte;
|
||||
|
||||
if (! quantity) {
|
||||
byte = 0;
|
||||
out.write(&byte, sizeof(byte));
|
||||
return;
|
||||
}
|
||||
|
||||
if (quantity->index == 0) {
|
||||
quantity->index = ++index;
|
||||
|
||||
byte = 1;
|
||||
out.write(&byte, sizeof(byte));
|
||||
|
||||
std::size_t size;
|
||||
mpz_export(buf, &size, 1, sizeof(int), 0, 0, MPZ(quantity));
|
||||
len = size * sizeof(int);
|
||||
#endif
|
||||
unsigned short len = size * sizeof(int);
|
||||
out.write((char *)&len, sizeof(len));
|
||||
|
||||
if (len) {
|
||||
out.write(buf, len);
|
||||
#ifndef WRITE_AMOUNTS_TEXTUALLY
|
||||
char negative = mpz_sgn(MPZ(quantity)) < 0 ? 1 : 0;
|
||||
out.write(&negative, sizeof(negative));
|
||||
#endif
|
||||
|
||||
byte = mpz_sgn(MPZ(quantity)) < 0 ? 1 : 0;
|
||||
out.write(&byte, sizeof(byte));
|
||||
|
||||
out.write((char *)&precision, sizeof(precision));
|
||||
}
|
||||
} else {
|
||||
len = 0;
|
||||
out.write((char *)&len, sizeof(len));
|
||||
assert(quantity->ref > 1);
|
||||
|
||||
// Since this value has already been written, we simply write
|
||||
// out a reference to which one it was.
|
||||
byte = 2;
|
||||
out.write(&byte, sizeof(byte));
|
||||
out.write((char *)&quantity->index, sizeof(quantity->index));
|
||||
}
|
||||
}
|
||||
|
||||
void amount_t::read_quantity(std::istream& in)
|
||||
{
|
||||
unsigned short len;
|
||||
in.read((char *)&len, sizeof(len));
|
||||
if (len) {
|
||||
assert(! quantity);
|
||||
|
||||
char byte;
|
||||
in.read(&byte, sizeof(byte));
|
||||
|
||||
if (byte == 0)
|
||||
return;
|
||||
|
||||
if (byte == 1) {
|
||||
_init();
|
||||
bigints.push_back(quantity);
|
||||
|
||||
unsigned short len;
|
||||
in.read((char *)&len, sizeof(len));
|
||||
in.read(buf, len);
|
||||
if (! quantity)
|
||||
_init();
|
||||
#ifdef WRITE_AMOUNTS_TEXTUALLY
|
||||
buf[len] = '\0';
|
||||
mpz_set_str(MPZ(quantity), buf, 10);
|
||||
#else
|
||||
mpz_import(MPZ(quantity), len / sizeof(int), 1, sizeof(int), 0, 0, buf);
|
||||
|
||||
char negative;
|
||||
in.read(&negative, sizeof(negative));
|
||||
mpz_import(MPZ(quantity), len / sizeof(int), 1, sizeof(int), 0, 0, buf);
|
||||
if (negative)
|
||||
mpz_neg(MPZ(quantity), MPZ(quantity));
|
||||
#endif
|
||||
|
||||
in.read((char *)&precision, sizeof(precision));
|
||||
} else {
|
||||
if (quantity)
|
||||
_clear();
|
||||
quantity = NULL;
|
||||
unsigned int index;
|
||||
in.read((char *)&index, sizeof(index));
|
||||
assert(index <= bigints.size());
|
||||
quantity = bigints[index - 1];
|
||||
quantity->ref++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
27
amount.h
27
amount.h
|
|
@ -13,15 +13,24 @@ class commodity_t;
|
|||
|
||||
class amount_t
|
||||
{
|
||||
typedef void * base_type;
|
||||
|
||||
void _init();
|
||||
void _copy(const amount_t& amt);
|
||||
void _clear();
|
||||
void _release();
|
||||
void _dup();
|
||||
void _resize(int prec);
|
||||
|
||||
void _clear() {
|
||||
if (quantity)
|
||||
_release();
|
||||
quantity = NULL;
|
||||
commodity = NULL;
|
||||
precision = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
base_type quantity; // amount, to MAX_PRECISION
|
||||
struct bigint_t;
|
||||
|
||||
bigint_t * quantity; // amount, to MAX_PRECISION
|
||||
unsigned short precision;
|
||||
commodity_t * commodity;
|
||||
|
||||
|
|
@ -40,14 +49,14 @@ class amount_t
|
|||
if (amt.quantity) {
|
||||
_copy(amt);
|
||||
} else {
|
||||
commodity = amt.commodity;
|
||||
precision = amt.precision;
|
||||
precision = 0;
|
||||
commodity = NULL;
|
||||
}
|
||||
}
|
||||
amount_t(const std::string& value) {
|
||||
amount_t(const std::string& value) : quantity(NULL) {
|
||||
parse(value);
|
||||
}
|
||||
amount_t(const char * value) {
|
||||
amount_t(const char * value) : quantity(NULL) {
|
||||
parse(value);
|
||||
}
|
||||
amount_t(const bool value);
|
||||
|
|
@ -58,7 +67,7 @@ class amount_t
|
|||
// destructor
|
||||
~amount_t() {
|
||||
if (quantity)
|
||||
_clear();
|
||||
_release();
|
||||
}
|
||||
|
||||
// assignment operator
|
||||
|
|
|
|||
17
binary.cc
17
binary.cc
|
|
@ -1,13 +1,7 @@
|
|||
#include "ledger.h"
|
||||
#include "binary.h"
|
||||
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <cctype>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define TIMELOG_SUPPORT 1
|
||||
|
|
@ -26,11 +20,11 @@ bool binary_parser_t::test(std::istream& in) const
|
|||
return magic == binary_magic_number;
|
||||
}
|
||||
|
||||
static std::vector<account_t *> accounts;
|
||||
static account_t::ident_t ident;
|
||||
static std::vector<commodity_t *> commodities;
|
||||
static commodity_t::ident_t c_ident;
|
||||
|
||||
static std::deque<account_t *> accounts;
|
||||
static account_t::ident_t ident;
|
||||
static std::deque<commodity_t *> commodities;
|
||||
static commodity_t::ident_t c_ident;
|
||||
std::deque<amount_t::bigint_t *> bigints;
|
||||
|
||||
#if RELEASE_LEVEL >= ALPHA
|
||||
#define read_binary_guard(in, id) { \
|
||||
|
|
@ -258,6 +252,7 @@ unsigned int read_binary_journal(std::istream& in,
|
|||
|
||||
accounts.clear();
|
||||
commodities.clear();
|
||||
bigints.clear();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
|
|
|||
4
binary.h
4
binary.h
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "parser.h"
|
||||
|
||||
#include <deque>
|
||||
|
||||
namespace ledger {
|
||||
|
||||
class binary_parser_t : public parser_t
|
||||
|
|
@ -16,6 +18,8 @@ class binary_parser_t : public parser_t
|
|||
const std::string * original_file = NULL);
|
||||
};
|
||||
|
||||
extern std::deque<amount_t::bigint_t *> bigints;
|
||||
|
||||
void write_binary_journal(std::ostream& out,
|
||||
journal_t * journal,
|
||||
strings_list * files = NULL);
|
||||
|
|
|
|||
13
debug.cc
13
debug.cc
|
|
@ -81,6 +81,19 @@ namespace ledger {
|
|||
std::ostream * debug_stream = &std::cerr;
|
||||
bool free_debug_stream = false;
|
||||
|
||||
bool _debug_active(const char * const cls) {
|
||||
if (char * debug = std::getenv("DEBUG_CLASS")) {
|
||||
static const char * error;
|
||||
static int erroffset;
|
||||
static int ovec[30];
|
||||
static pcre * class_regexp = pcre_compile(debug, PCRE_CASELESS,
|
||||
&error, &erroffset, NULL);
|
||||
return pcre_exec(class_regexp, NULL, cls, std::strlen(cls),
|
||||
0, 0, ovec, 30) >= 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct init_streams {
|
||||
init_streams() {
|
||||
// If debugging is enabled and DEBUG_FILE is set, all debugging
|
||||
|
|
|
|||
13
debug.h
13
debug.h
|
|
@ -68,18 +68,7 @@ extern std::ostream * warning_stream;
|
|||
extern std::ostream * debug_stream;
|
||||
extern bool free_debug_stream;
|
||||
|
||||
inline bool _debug_active(const char * const cls) {
|
||||
if (char * debug = std::getenv("DEBUG_CLASS")) {
|
||||
static const char * error;
|
||||
static int erroffset;
|
||||
static int ovec[30];
|
||||
static pcre * class_regexp = pcre_compile(debug, PCRE_CASELESS,
|
||||
&error, &erroffset, NULL);
|
||||
return pcre_exec(class_regexp, NULL, cls, std::strlen(cls),
|
||||
0, 0, ovec, 30) >= 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool _debug_active(const char * const cls);
|
||||
|
||||
#define DEBUG_CLASS(cls) static const char * const _debug_cls = (cls)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue