summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--amount.cc288
-rw-r--r--amount.h27
-rw-r--r--binary.cc17
-rw-r--r--binary.h4
-rw-r--r--debug.cc13
-rw-r--r--debug.h13
6 files changed, 234 insertions, 128 deletions
diff --git a/amount.cc b/amount.cc
index d975b7fd..ccad248b 100644
--- a/amount.cc
+++ b/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) {
+ quantity = new bigint_t(true_value);
+ precision = 0;
commodity = commodity_t::null_commodity;
+ } else {
+ quantity = NULL;
precision = 0;
- quantity = new MP_INT;
- mpz_init_set(MPZ(quantity), true_value);
+ commodity = NULL;
}
}
amount_t::amount_t(const int value)
- : quantity(NULL), commodity(NULL)
{
if (value != 0) {
_init();
+ mpz_set_si(MPZ(quantity), value);
+ precision = 0;
commodity = commodity_t::null_commodity;
+ } else {
+ quantity = NULL;
precision = 0;
- mpz_set_si(MPZ(quantity), value);
+ commodity = NULL;
}
}
amount_t::amount_t(const unsigned int value)
- : quantity(NULL), commodity(NULL)
{
if (value != 0) {
_init();
+ mpz_set_ui(MPZ(quantity), value);
+ precision = 0;
commodity = commodity_t::null_commodity;
+ } else {
+ quantity = NULL;
precision = 0;
- mpz_set_ui(MPZ(quantity), value);
+ commodity = NULL;
}
}
amount_t::amount_t(const double value)
- : quantity(NULL), commodity(NULL)
{
if (value != 0.0) {
_init();
+ mpz_set_d(MPZ(quantity), value);
+ // jww (2004-08-20): How do I calculate this?
+ precision = 0;
commodity = commodity_t::null_commodity;
- // jww (2004-08-20): How do I calculate?
+ } else {
+ quantity = NULL;
precision = 0;
- mpz_set_d(MPZ(quantity), value);
+ 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::_copy(const amount_t& amt)
+void amount_t::_dup()
{
- if (quantity) {
- mpz_set(MPZ(quantity), MPZ(amt.quantity));
- } else {
- quantity = new MP_INT;
- mpz_init_set(MPZ(quantity), MPZ(amt.quantity));
+ 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)
+ _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++;
}
}
diff --git a/amount.h b/amount.h
index 2e8e526e..21d5bbfe 100644
--- a/amount.h
+++ b/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
diff --git a/binary.cc b/binary.cc
index 6c31f574..61276a7c 100644
--- a/binary.cc
+++ b/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;
}
diff --git a/binary.h b/binary.h
index 4b502df5..a1ab60c2 100644
--- a/binary.h
+++ b/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);
diff --git a/debug.cc b/debug.cc
index 02613210..cbe56d0d 100644
--- a/debug.cc
+++ b/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
diff --git a/debug.h b/debug.h
index 75c7b5b3..2873ef7a 100644
--- a/debug.h
+++ b/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)