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 "ledger.h"
|
||||||
|
#include "binary.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#include "gmp.h"
|
#include <deque>
|
||||||
|
|
||||||
#define MPZ(x) ((MP_INT *)(x))
|
#include "gmp.h"
|
||||||
|
|
||||||
namespace ledger {
|
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 divisor;
|
||||||
static mpz_t true_value;
|
static mpz_t true_value;
|
||||||
|
|
||||||
static struct init_amounts {
|
static struct init_amounts {
|
||||||
init_amounts() {
|
init_amounts() {
|
||||||
|
mpz_init(temp);
|
||||||
mpz_init(divisor);
|
mpz_init(divisor);
|
||||||
mpz_init(true_value);
|
mpz_init(true_value);
|
||||||
mpz_set_ui(true_value, 1);
|
mpz_set_ui(true_value, 1);
|
||||||
|
|
@ -21,6 +67,7 @@ static struct init_amounts {
|
||||||
~init_amounts() {
|
~init_amounts() {
|
||||||
mpz_clear(true_value);
|
mpz_clear(true_value);
|
||||||
mpz_clear(divisor);
|
mpz_clear(divisor);
|
||||||
|
mpz_clear(temp);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} initializer;
|
} 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)
|
amount_t::amount_t(const bool value)
|
||||||
: quantity(NULL), commodity(NULL)
|
|
||||||
{
|
{
|
||||||
if (value) {
|
if (value) {
|
||||||
commodity = commodity_t::null_commodity;
|
quantity = new bigint_t(true_value);
|
||||||
precision = 0;
|
precision = 0;
|
||||||
quantity = new MP_INT;
|
commodity = commodity_t::null_commodity;
|
||||||
mpz_init_set(MPZ(quantity), true_value);
|
} else {
|
||||||
|
quantity = NULL;
|
||||||
|
precision = 0;
|
||||||
|
commodity = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
amount_t::amount_t(const int value)
|
amount_t::amount_t(const int value)
|
||||||
: quantity(NULL), commodity(NULL)
|
|
||||||
{
|
{
|
||||||
if (value != 0) {
|
if (value != 0) {
|
||||||
_init();
|
_init();
|
||||||
commodity = commodity_t::null_commodity;
|
|
||||||
precision = 0;
|
|
||||||
mpz_set_si(MPZ(quantity), value);
|
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)
|
amount_t::amount_t(const unsigned int value)
|
||||||
: quantity(NULL), commodity(NULL)
|
|
||||||
{
|
{
|
||||||
if (value != 0) {
|
if (value != 0) {
|
||||||
_init();
|
_init();
|
||||||
commodity = commodity_t::null_commodity;
|
|
||||||
precision = 0;
|
|
||||||
mpz_set_ui(MPZ(quantity), value);
|
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)
|
amount_t::amount_t(const double value)
|
||||||
: quantity(NULL), commodity(NULL)
|
|
||||||
{
|
{
|
||||||
if (value != 0.0) {
|
if (value != 0.0) {
|
||||||
_init();
|
_init();
|
||||||
commodity = commodity_t::null_commodity;
|
|
||||||
// jww (2004-08-20): How do I calculate?
|
|
||||||
precision = 0;
|
|
||||||
mpz_set_d(MPZ(quantity), value);
|
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));
|
if (--quantity->ref == 0)
|
||||||
delete (MP_INT *) quantity;
|
delete quantity;
|
||||||
}
|
}
|
||||||
|
|
||||||
void amount_t::_init()
|
void amount_t::_init()
|
||||||
{
|
{
|
||||||
quantity = new MP_INT;
|
quantity = new bigint_t;
|
||||||
mpz_init(MPZ(quantity));
|
}
|
||||||
|
|
||||||
|
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)
|
void amount_t::_copy(const amount_t& amt)
|
||||||
{
|
{
|
||||||
if (quantity) {
|
if (quantity)
|
||||||
mpz_set(MPZ(quantity), MPZ(amt.quantity));
|
_release();
|
||||||
} else {
|
|
||||||
quantity = new MP_INT;
|
quantity = amt.quantity;
|
||||||
mpz_init_set(MPZ(quantity), MPZ(amt.quantity));
|
quantity->ref++;
|
||||||
}
|
|
||||||
commodity = amt.commodity;
|
commodity = amt.commodity;
|
||||||
precision = amt.precision;
|
precision = amt.precision;
|
||||||
assert(commodity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
amount_t& amount_t::operator=(const std::string& value)
|
amount_t& amount_t::operator=(const std::string& value)
|
||||||
|
|
@ -167,29 +232,30 @@ amount_t& amount_t::operator=(const char * value)
|
||||||
// assignment operator
|
// assignment operator
|
||||||
amount_t& amount_t::operator=(const amount_t& amt)
|
amount_t& amount_t::operator=(const amount_t& amt)
|
||||||
{
|
{
|
||||||
if (amt.quantity) {
|
if (amt.quantity)
|
||||||
_copy(amt);
|
_copy(amt);
|
||||||
} else {
|
else if (quantity)
|
||||||
commodity = amt.commodity;
|
_clear();
|
||||||
precision = amt.precision;
|
|
||||||
}
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
amount_t& amount_t::operator=(const bool value)
|
amount_t& amount_t::operator=(const bool value)
|
||||||
{
|
{
|
||||||
if (! value) {
|
if (! value) {
|
||||||
if (quantity) {
|
if (quantity)
|
||||||
_clear();
|
_clear();
|
||||||
quantity = NULL;
|
|
||||||
commodity = NULL;
|
|
||||||
precision = 0;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
commodity = commodity_t::null_commodity;
|
commodity = commodity_t::null_commodity;
|
||||||
precision = 0;
|
precision = 0;
|
||||||
quantity = new MP_INT;
|
if (! quantity) {
|
||||||
mpz_init_set(MPZ(quantity), true_value);
|
_init();
|
||||||
|
}
|
||||||
|
else if (quantity->ref > 1) {
|
||||||
|
_release();
|
||||||
|
_init();
|
||||||
|
}
|
||||||
|
mpz_set(MPZ(quantity), true_value);
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
@ -197,15 +263,18 @@ amount_t& amount_t::operator=(const bool value)
|
||||||
amount_t& amount_t::operator=(const int value)
|
amount_t& amount_t::operator=(const int value)
|
||||||
{
|
{
|
||||||
if (value == 0) {
|
if (value == 0) {
|
||||||
if (quantity) {
|
if (quantity)
|
||||||
_clear();
|
_clear();
|
||||||
quantity = NULL;
|
|
||||||
commodity = NULL;
|
|
||||||
precision = 0;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
commodity = commodity_t::null_commodity;
|
commodity = commodity_t::null_commodity;
|
||||||
precision = 0;
|
precision = 0;
|
||||||
|
if (! quantity) {
|
||||||
|
_init();
|
||||||
|
}
|
||||||
|
else if (quantity->ref > 1) {
|
||||||
|
_release();
|
||||||
|
_init();
|
||||||
|
}
|
||||||
mpz_set_si(MPZ(quantity), value);
|
mpz_set_si(MPZ(quantity), value);
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
|
|
@ -214,15 +283,18 @@ amount_t& amount_t::operator=(const int value)
|
||||||
amount_t& amount_t::operator=(const unsigned int value)
|
amount_t& amount_t::operator=(const unsigned int value)
|
||||||
{
|
{
|
||||||
if (value == 0) {
|
if (value == 0) {
|
||||||
if (quantity) {
|
if (quantity)
|
||||||
_clear();
|
_clear();
|
||||||
quantity = NULL;
|
|
||||||
commodity = NULL;
|
|
||||||
precision = 0;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
commodity = commodity_t::null_commodity;
|
commodity = commodity_t::null_commodity;
|
||||||
precision = 0;
|
precision = 0;
|
||||||
|
if (! quantity) {
|
||||||
|
_init();
|
||||||
|
}
|
||||||
|
else if (quantity->ref > 1) {
|
||||||
|
_release();
|
||||||
|
_init();
|
||||||
|
}
|
||||||
mpz_set_ui(MPZ(quantity), value);
|
mpz_set_ui(MPZ(quantity), value);
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
|
|
@ -231,16 +303,19 @@ amount_t& amount_t::operator=(const unsigned int value)
|
||||||
amount_t& amount_t::operator=(const double value)
|
amount_t& amount_t::operator=(const double value)
|
||||||
{
|
{
|
||||||
if (value == 0.0) {
|
if (value == 0.0) {
|
||||||
if (quantity) {
|
if (quantity)
|
||||||
_clear();
|
_clear();
|
||||||
quantity = NULL;
|
|
||||||
commodity = NULL;
|
|
||||||
precision = 0;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
commodity = commodity_t::null_commodity;
|
commodity = commodity_t::null_commodity;
|
||||||
// jww (2004-08-20): How do I calculate?
|
// jww (2004-08-20): How do I calculate?
|
||||||
precision = 0;
|
precision = 0;
|
||||||
|
if (! quantity) {
|
||||||
|
_init();
|
||||||
|
}
|
||||||
|
else if (quantity->ref > 1) {
|
||||||
|
_release();
|
||||||
|
_init();
|
||||||
|
}
|
||||||
mpz_set_d(MPZ(quantity), value);
|
mpz_set_d(MPZ(quantity), value);
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
|
|
@ -252,6 +327,8 @@ void amount_t::_resize(int prec)
|
||||||
if (prec == precision)
|
if (prec == precision)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_dup();
|
||||||
|
|
||||||
if (prec < precision) {
|
if (prec < precision) {
|
||||||
mpz_ui_pow_ui(divisor, 10, precision - prec);
|
mpz_ui_pow_ui(divisor, 10, precision - prec);
|
||||||
mpz_tdiv_q(MPZ(quantity), MPZ(quantity), divisor);
|
mpz_tdiv_q(MPZ(quantity), MPZ(quantity), divisor);
|
||||||
|
|
@ -272,6 +349,8 @@ amount_t& amount_t::operator OP(const amount_t& amt) \
|
||||||
_init(); \
|
_init(); \
|
||||||
commodity = amt.commodity; \
|
commodity = amt.commodity; \
|
||||||
precision = amt.precision; \
|
precision = amt.precision; \
|
||||||
|
} else { \
|
||||||
|
_dup(); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
if (commodity != amt.commodity) \
|
if (commodity != amt.commodity) \
|
||||||
|
|
@ -298,8 +377,10 @@ DEF_OPERATOR(-=, mpz_sub)
|
||||||
// unary negation
|
// unary negation
|
||||||
amount_t& amount_t::negate()
|
amount_t& amount_t::negate()
|
||||||
{
|
{
|
||||||
if (quantity)
|
if (quantity) {
|
||||||
|
_dup();
|
||||||
mpz_ui_sub(MPZ(quantity), 0, MPZ(quantity));
|
mpz_ui_sub(MPZ(quantity), 0, MPZ(quantity));
|
||||||
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -454,12 +535,10 @@ amount_t::operator bool() const
|
||||||
return mpz_sgn(MPZ(quantity)) != 0;
|
return mpz_sgn(MPZ(quantity)) != 0;
|
||||||
} else {
|
} else {
|
||||||
assert(commodity);
|
assert(commodity);
|
||||||
mpz_t temp;
|
mpz_set(temp, MPZ(quantity));
|
||||||
mpz_init_set(temp, MPZ(quantity));
|
|
||||||
mpz_ui_pow_ui(divisor, 10, precision - commodity->precision);
|
mpz_ui_pow_ui(divisor, 10, precision - commodity->precision);
|
||||||
mpz_tdiv_q(temp, temp, divisor);
|
mpz_tdiv_q(temp, temp, divisor);
|
||||||
bool zero = mpz_sgn(temp) == 0;
|
bool zero = mpz_sgn(temp) == 0;
|
||||||
mpz_clear(temp);
|
|
||||||
return ! zero;
|
return ! zero;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -481,6 +560,8 @@ amount_t& amount_t::operator*=(const amount_t& amt)
|
||||||
if (! amt.quantity || ! quantity)
|
if (! amt.quantity || ! quantity)
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
|
_dup();
|
||||||
|
|
||||||
mpz_mul(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity));
|
mpz_mul(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity));
|
||||||
precision += amt.precision;
|
precision += amt.precision;
|
||||||
|
|
||||||
|
|
@ -495,6 +576,8 @@ amount_t& amount_t::operator/=(const amount_t& amt)
|
||||||
if (! amt.quantity)
|
if (! amt.quantity)
|
||||||
throw amount_error("Divide by zero");
|
throw amount_error("Divide by zero");
|
||||||
|
|
||||||
|
_dup();
|
||||||
|
|
||||||
// Increase the value's precision, to capture fractional parts after
|
// Increase the value's precision, to capture fractional parts after
|
||||||
// the divide.
|
// the divide.
|
||||||
mpz_ui_pow_ui(divisor, 10, amt.precision + 6);
|
mpz_ui_pow_ui(divisor, 10, amt.precision + 6);
|
||||||
|
|
@ -514,6 +597,7 @@ amount_t amount_t::round(int prec) const
|
||||||
return *this;
|
return *this;
|
||||||
} else {
|
} else {
|
||||||
amount_t temp = *this;
|
amount_t temp = *this;
|
||||||
|
temp._dup();
|
||||||
mpz_round(MPZ(temp.quantity), MPZ(temp.quantity),
|
mpz_round(MPZ(temp.quantity), MPZ(temp.quantity),
|
||||||
precision, prec == -1 ? commodity->precision : prec);
|
precision, prec == -1 ? commodity->precision : prec);
|
||||||
return temp;
|
return temp;
|
||||||
|
|
@ -591,9 +675,6 @@ std::ostream& operator<<(std::ostream& out, const amount_t& amt)
|
||||||
std::list<std::string> strs;
|
std::list<std::string> strs;
|
||||||
char buf[4];
|
char buf[4];
|
||||||
|
|
||||||
mpz_t temp;
|
|
||||||
mpz_init(temp);
|
|
||||||
|
|
||||||
for (int powers = 0; true; powers += 3) {
|
for (int powers = 0; true; powers += 3) {
|
||||||
if (powers > 0) {
|
if (powers > 0) {
|
||||||
mpz_ui_pow_ui(divisor, 10, powers);
|
mpz_ui_pow_ui(divisor, 10, powers);
|
||||||
|
|
@ -622,8 +703,6 @@ std::ostream& operator<<(std::ostream& out, const amount_t& amt)
|
||||||
|
|
||||||
printed = true;
|
printed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
mpz_clear(temp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (amt.commodity->precision) {
|
if (amt.commodity->precision) {
|
||||||
|
|
@ -696,8 +775,9 @@ void amount_t::parse(std::istream& in)
|
||||||
std::string quant;
|
std::string quant;
|
||||||
unsigned int flags = COMMODITY_STYLE_DEFAULTS;;
|
unsigned int flags = COMMODITY_STYLE_DEFAULTS;;
|
||||||
|
|
||||||
if (! quantity)
|
if (quantity)
|
||||||
_init();
|
_release();
|
||||||
|
_init();
|
||||||
|
|
||||||
char c = peek_next_nonws(in);
|
char c = peek_next_nonws(in);
|
||||||
if (std::isdigit(c) || c == '.' || c == '-') {
|
if (std::isdigit(c) || c == '.' || c == '-') {
|
||||||
|
|
@ -771,64 +851,80 @@ void amount_t::parse(std::istream& in)
|
||||||
delete[] buf;
|
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 char buf[4096];
|
||||||
|
static int index = 0;
|
||||||
|
|
||||||
void amount_t::write_quantity(std::ostream& out) const
|
void amount_t::write_quantity(std::ostream& out) const
|
||||||
{
|
{
|
||||||
unsigned short len;
|
char byte;
|
||||||
if (quantity) {
|
|
||||||
#ifdef WRITE_AMOUNTS_TEXTUALLY
|
if (! quantity) {
|
||||||
mpz_get_str(buf, 10, MPZ(quantity));
|
byte = 0;
|
||||||
len = std::strlen(buf);
|
out.write(&byte, sizeof(byte));
|
||||||
#else
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quantity->index == 0) {
|
||||||
|
quantity->index = ++index;
|
||||||
|
|
||||||
|
byte = 1;
|
||||||
|
out.write(&byte, sizeof(byte));
|
||||||
|
|
||||||
std::size_t size;
|
std::size_t size;
|
||||||
mpz_export(buf, &size, 1, sizeof(int), 0, 0, MPZ(quantity));
|
mpz_export(buf, &size, 1, sizeof(int), 0, 0, MPZ(quantity));
|
||||||
len = size * sizeof(int);
|
unsigned short len = size * sizeof(int);
|
||||||
#endif
|
|
||||||
out.write((char *)&len, sizeof(len));
|
out.write((char *)&len, sizeof(len));
|
||||||
|
|
||||||
if (len) {
|
if (len) {
|
||||||
out.write(buf, len);
|
out.write(buf, len);
|
||||||
#ifndef WRITE_AMOUNTS_TEXTUALLY
|
|
||||||
char negative = mpz_sgn(MPZ(quantity)) < 0 ? 1 : 0;
|
byte = mpz_sgn(MPZ(quantity)) < 0 ? 1 : 0;
|
||||||
out.write(&negative, sizeof(negative));
|
out.write(&byte, sizeof(byte));
|
||||||
#endif
|
|
||||||
out.write((char *)&precision, sizeof(precision));
|
out.write((char *)&precision, sizeof(precision));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
len = 0;
|
assert(quantity->ref > 1);
|
||||||
out.write((char *)&len, sizeof(len));
|
|
||||||
|
// 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)
|
void amount_t::read_quantity(std::istream& in)
|
||||||
{
|
{
|
||||||
unsigned short len;
|
assert(! quantity);
|
||||||
in.read((char *)&len, sizeof(len));
|
|
||||||
if (len) {
|
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);
|
in.read(buf, len);
|
||||||
if (! quantity)
|
mpz_import(MPZ(quantity), len / sizeof(int), 1, sizeof(int), 0, 0, buf);
|
||||||
_init();
|
|
||||||
#ifdef WRITE_AMOUNTS_TEXTUALLY
|
|
||||||
buf[len] = '\0';
|
|
||||||
mpz_set_str(MPZ(quantity), buf, 10);
|
|
||||||
#else
|
|
||||||
char negative;
|
char negative;
|
||||||
in.read(&negative, sizeof(negative));
|
in.read(&negative, sizeof(negative));
|
||||||
mpz_import(MPZ(quantity), len / sizeof(int), 1, sizeof(int), 0, 0, buf);
|
|
||||||
if (negative)
|
if (negative)
|
||||||
mpz_neg(MPZ(quantity), MPZ(quantity));
|
mpz_neg(MPZ(quantity), MPZ(quantity));
|
||||||
#endif
|
|
||||||
in.read((char *)&precision, sizeof(precision));
|
in.read((char *)&precision, sizeof(precision));
|
||||||
} else {
|
} else {
|
||||||
if (quantity)
|
unsigned int index;
|
||||||
_clear();
|
in.read((char *)&index, sizeof(index));
|
||||||
quantity = NULL;
|
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
|
class amount_t
|
||||||
{
|
{
|
||||||
typedef void * base_type;
|
|
||||||
|
|
||||||
void _init();
|
void _init();
|
||||||
void _copy(const amount_t& amt);
|
void _copy(const amount_t& amt);
|
||||||
void _clear();
|
void _release();
|
||||||
|
void _dup();
|
||||||
void _resize(int prec);
|
void _resize(int prec);
|
||||||
|
|
||||||
|
void _clear() {
|
||||||
|
if (quantity)
|
||||||
|
_release();
|
||||||
|
quantity = NULL;
|
||||||
|
commodity = NULL;
|
||||||
|
precision = 0;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
base_type quantity; // amount, to MAX_PRECISION
|
struct bigint_t;
|
||||||
|
|
||||||
|
bigint_t * quantity; // amount, to MAX_PRECISION
|
||||||
unsigned short precision;
|
unsigned short precision;
|
||||||
commodity_t * commodity;
|
commodity_t * commodity;
|
||||||
|
|
||||||
|
|
@ -40,14 +49,14 @@ class amount_t
|
||||||
if (amt.quantity) {
|
if (amt.quantity) {
|
||||||
_copy(amt);
|
_copy(amt);
|
||||||
} else {
|
} else {
|
||||||
commodity = amt.commodity;
|
precision = 0;
|
||||||
precision = amt.precision;
|
commodity = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
amount_t(const std::string& value) {
|
amount_t(const std::string& value) : quantity(NULL) {
|
||||||
parse(value);
|
parse(value);
|
||||||
}
|
}
|
||||||
amount_t(const char * value) {
|
amount_t(const char * value) : quantity(NULL) {
|
||||||
parse(value);
|
parse(value);
|
||||||
}
|
}
|
||||||
amount_t(const bool value);
|
amount_t(const bool value);
|
||||||
|
|
@ -58,7 +67,7 @@ class amount_t
|
||||||
// destructor
|
// destructor
|
||||||
~amount_t() {
|
~amount_t() {
|
||||||
if (quantity)
|
if (quantity)
|
||||||
_clear();
|
_release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// assignment operator
|
// assignment operator
|
||||||
|
|
|
||||||
17
binary.cc
17
binary.cc
|
|
@ -1,13 +1,7 @@
|
||||||
#include "ledger.h"
|
#include "ledger.h"
|
||||||
#include "binary.h"
|
#include "binary.h"
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <fstream>
|
|
||||||
#include <sstream>
|
|
||||||
#include <cstring>
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <cctype>
|
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#define TIMELOG_SUPPORT 1
|
#define TIMELOG_SUPPORT 1
|
||||||
|
|
@ -26,11 +20,11 @@ bool binary_parser_t::test(std::istream& in) const
|
||||||
return magic == binary_magic_number;
|
return magic == binary_magic_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<account_t *> accounts;
|
static std::deque<account_t *> accounts;
|
||||||
static account_t::ident_t ident;
|
static account_t::ident_t ident;
|
||||||
static std::vector<commodity_t *> commodities;
|
static std::deque<commodity_t *> commodities;
|
||||||
static commodity_t::ident_t c_ident;
|
static commodity_t::ident_t c_ident;
|
||||||
|
std::deque<amount_t::bigint_t *> bigints;
|
||||||
|
|
||||||
#if RELEASE_LEVEL >= ALPHA
|
#if RELEASE_LEVEL >= ALPHA
|
||||||
#define read_binary_guard(in, id) { \
|
#define read_binary_guard(in, id) { \
|
||||||
|
|
@ -258,6 +252,7 @@ unsigned int read_binary_journal(std::istream& in,
|
||||||
|
|
||||||
accounts.clear();
|
accounts.clear();
|
||||||
commodities.clear();
|
commodities.clear();
|
||||||
|
bigints.clear();
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
4
binary.h
4
binary.h
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
class binary_parser_t : public parser_t
|
class binary_parser_t : public parser_t
|
||||||
|
|
@ -16,6 +18,8 @@ class binary_parser_t : public parser_t
|
||||||
const std::string * original_file = NULL);
|
const std::string * original_file = NULL);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern std::deque<amount_t::bigint_t *> bigints;
|
||||||
|
|
||||||
void write_binary_journal(std::ostream& out,
|
void write_binary_journal(std::ostream& out,
|
||||||
journal_t * journal,
|
journal_t * journal,
|
||||||
strings_list * files = NULL);
|
strings_list * files = NULL);
|
||||||
|
|
|
||||||
13
debug.cc
13
debug.cc
|
|
@ -81,6 +81,19 @@ namespace ledger {
|
||||||
std::ostream * debug_stream = &std::cerr;
|
std::ostream * debug_stream = &std::cerr;
|
||||||
bool free_debug_stream = false;
|
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 {
|
static struct init_streams {
|
||||||
init_streams() {
|
init_streams() {
|
||||||
// If debugging is enabled and DEBUG_FILE is set, all debugging
|
// 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 std::ostream * debug_stream;
|
||||||
extern bool free_debug_stream;
|
extern bool free_debug_stream;
|
||||||
|
|
||||||
inline bool _debug_active(const char * const cls) {
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DEBUG_CLASS(cls) static const char * const _debug_cls = (cls)
|
#define DEBUG_CLASS(cls) static const char * const _debug_cls = (cls)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue