summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/TODO5
-rw-r--r--src/amount.cc103
-rw-r--r--src/amount.h19
-rw-r--r--src/binary.cc30
-rw-r--r--src/binary.h22
5 files changed, 96 insertions, 83 deletions
diff --git a/src/TODO b/src/TODO
index 5ad232dd..3ea808d5 100644
--- a/src/TODO
+++ b/src/TODO
@@ -1,3 +1,8 @@
- Add tracing code for functions that records call count and total
time spent, as well as average time per call. This would implement
selective profiling.
+
+- Make sure that if any constructors cause memory to be allocated,
+ that the memory is held by an auto_ptr until the constructor is
+ done; otherwise, an exception raised from within the constructor
+ will not call the destructor to free the memory.
diff --git a/src/amount.cc b/src/amount.cc
index 70d1ac4f..0025fbd9 100644
--- a/src/amount.cc
+++ b/src/amount.cc
@@ -131,20 +131,6 @@ void amount_t::shutdown()
}
}
-void amount_t::_init()
-{
- // This is only called on an initialized amount by amount_t::parse.
-
- if (! quantity) {
- quantity = new bigint_t;
- }
- else if (quantity->ref > 1) {
- _release();
- quantity = new bigint_t;
- }
- commodity_ = NULL;
-}
-
void amount_t::_copy(const amount_t& amt)
{
if (quantity != amt.quantity) {
@@ -183,13 +169,9 @@ void amount_t::_resize(precision_t prec)
_dup();
- if (prec < quantity->prec) {
- mpz_ui_pow_ui(divisor, 10, quantity->prec - prec);
- mpz_tdiv_q(MPZ(quantity), MPZ(quantity), divisor);
- } else {
- mpz_ui_pow_ui(divisor, 10, prec - quantity->prec);
- mpz_mul(MPZ(quantity), MPZ(quantity), divisor);
- }
+ assert(prec > quantity->prec);
+ mpz_ui_pow_ui(divisor, 10, prec - quantity->prec);
+ mpz_mul(MPZ(quantity), MPZ(quantity), divisor);
quantity->prec = prec;
}
@@ -359,7 +341,7 @@ int amount_t::compare(const amount_t& amt) const
return mpz_cmp(MPZ(quantity), MPZ(amt.quantity));
}
else if (quantity->prec < amt.quantity->prec) {
- amount_t t = *this;
+ amount_t t(*this);
t._resize(amt.quantity->prec);
return mpz_cmp(MPZ(t.quantity), MPZ(amt.quantity));
}
@@ -607,11 +589,11 @@ amount_t& amount_t::in_place_negate()
amount_t amount_t::round(precision_t prec) const
{
- amount_t t = *this;
-
if (! quantity)
throw_(amount_error, "Cannot round an uninitialized amount");
+ amount_t t(*this);
+
if (quantity->prec <= prec) {
if (quantity && quantity->has_flags(BIGINT_KEEP_PREC)) {
t._dup();
@@ -637,7 +619,7 @@ amount_t amount_t::unround() const
else if (quantity->has_flags(BIGINT_KEEP_PREC))
return *this;
- amount_t t = *this;
+ amount_t t(*this);
t._dup();
t.quantity->add_flags(BIGINT_KEEP_PREC);
@@ -915,7 +897,23 @@ void amount_t::parse(std::istream& in, flags_t flags)
if (quant.empty())
throw_(amount_error, "No quantity specified for amount");
- _init(); // this will reuse a current value
+ // Allocate memory for the amount's quantity value. We have to
+ // monitor the allocation in an auto_ptr because this function gets
+ // called sometimes from amount_t's constructor; and if there is an
+ // exeception thrown by any of the function calls after this point,
+ // the destructor will never be called and the memory never freed.
+
+ std::auto_ptr<bigint_t> safe_holder;
+
+ if (! quantity) {
+ quantity = new bigint_t;
+ safe_holder.reset(quantity);
+ }
+ else if (quantity->ref > 1) {
+ _release();
+ quantity = new bigint_t;
+ safe_holder.reset(quantity);
+ }
// Create the commodity if has not already been seen, and update the
// precision if something greater was used for the quantity.
@@ -965,9 +963,9 @@ void amount_t::parse(std::istream& in, flags_t flags)
// Set the commodity's flags and precision accordingly
- if (commodity_ &&
- (newly_created || ! (flags & AMOUNT_PARSE_NO_MIGRATE))) {
+ if (commodity_ && (newly_created || ! (flags & AMOUNT_PARSE_NO_MIGRATE))) {
commodity().add_flags(comm_flags);
+
if (quantity->prec > commodity().precision())
commodity().set_precision(quantity->prec);
}
@@ -1004,6 +1002,8 @@ void amount_t::parse(std::istream& in, flags_t flags)
if (! (flags & AMOUNT_PARSE_NO_REDUCE))
in_place_reduce();
+
+ safe_holder.release(); // `this->quantity' owns the pointer
}
void amount_t::parse_conversion(const string& larger_str,
@@ -1201,8 +1201,6 @@ void amount_t::print(std::ostream& _out, bool omit_commodity,
// entire amount string, and not just the first part.
_out << out.str();
-
- return;
}
@@ -1225,7 +1223,7 @@ void amount_t::read(std::istream& in)
else if (ident == 0)
commodity_ = current_pool->null_commodity;
else {
- commodity_ = current_pool->find(ident - 1);
+ commodity_ = current_pool->find(ident);
assert(commodity_);
}
@@ -1234,10 +1232,7 @@ void amount_t::read(std::istream& in)
char byte;
in.read(&byte, sizeof(byte));
- if (byte == 0) {
- quantity = NULL;
- }
- else if (byte == 1) {
+ if (byte < 3) {
quantity = new bigint_t;
unsigned short len;
@@ -1263,7 +1258,7 @@ void amount_t::read(std::istream& in)
}
}
-void amount_t::read(char *& data)
+void amount_t::read(const char *& data)
{
// Read in the commodity for this amount
@@ -1274,7 +1269,7 @@ void amount_t::read(char *& data)
else if (ident == 0)
commodity_ = current_pool->null_commodity;
else {
- commodity_ = current_pool->find(ident - 1);
+ commodity_ = current_pool->find(ident);
assert(commodity_);
}
@@ -1282,12 +1277,13 @@ void amount_t::read(char *& data)
char byte = *data++;;
- if (byte == 0) {
- quantity = NULL;
- }
- else if (byte == 1) {
- quantity = new((bigint_t *)bigints_next) bigint_t;
- bigints_next += sizeof(bigint_t);
+ if (byte < 3) {
+ if (byte == 2) {
+ quantity = new((bigint_t *)bigints_next) bigint_t;
+ bigints_next += sizeof(bigint_t);
+ } else {
+ quantity = new bigint_t;
+ }
unsigned short len = *((unsigned short *) data);
data += sizeof(unsigned short);
@@ -1303,7 +1299,9 @@ void amount_t::read(char *& data)
data += sizeof(precision_t);
quantity->set_flags(*((flags_t *) data));
data += sizeof(flags_t);
- quantity->add_flags(BIGINT_BULK_ALLOC);
+
+ if (byte == 2)
+ quantity->add_flags(BIGINT_BULK_ALLOC);
} else {
uint_fast32_t index = *((uint_fast32_t *) data);
data += sizeof(uint_fast32_t);
@@ -1315,7 +1313,7 @@ void amount_t::read(char *& data)
}
}
-void amount_t::write(std::ostream& out) const
+void amount_t::write(std::ostream& out, bool optimized) const
{
// Write out the commodity for this amount
@@ -1331,11 +1329,14 @@ void amount_t::write(std::ostream& out) const
char byte;
- if (quantity->index == 0) {
- quantity->index = ++bigints_index;
- bigints_count++;
-
- byte = 1;
+ if (! optimized || quantity->index == 0) {
+ if (optimized) {
+ quantity->index = ++bigints_index; // if !optimized, this is garbage
+ bigints_count++;
+ byte = 2;
+ } else {
+ byte = 1;
+ }
out.write(&byte, sizeof(byte));
std::size_t size;
@@ -1359,7 +1360,7 @@ void amount_t::write(std::ostream& out) const
// Since this value has already been written, we simply write
// out a reference to which one it was.
- byte = 2;
+ byte = 3;
out.write(&byte, sizeof(byte));
out.write((char *)&quantity->index, sizeof(quantity->index));
}
diff --git a/src/amount.h b/src/amount.h
index 2f360f72..10659f1f 100644
--- a/src/amount.h
+++ b/src/amount.h
@@ -141,7 +141,6 @@ public:
static bool stream_fullstrings;
protected:
- void _init();
void _copy(const amount_t& amt);
void _dup();
void _resize(precision_t prec);
@@ -326,7 +325,7 @@ public:
precision_t precision() const;
amount_t negate() const {
- amount_t temp = *this;
+ amount_t temp(*this);
temp.in_place_negate();
return temp;
}
@@ -575,6 +574,7 @@ public:
void parse(const string& str, flags_t flags = 0) {
std::istringstream stream(str);
parse(stream, flags);
+ assert(stream.eof());
}
static void parse_conversion(const string& larger_str,
@@ -616,12 +616,17 @@ public:
* an input stream into a buffer. It advances the pointer passed in
* to the end of the deserialized amount.
*
- * write(ostream) writes an amount to an output stream in a compact
- * binary format.
+ * write(ostream, [bool]) writes an amount to an output stream in a
+ * compact binary format. If the second parameter is true,
+ * quantities with multiple reference counts will be written in an
+ * optimized fashion. NOTE: This form of usage is valid only for
+ * the binary journal writer, it should not be used otherwise, as it
+ * has strict requirements for reading that only the binary reader
+ * knows about.
*/
void read(std::istream& in);
- void read(char *& data);
- void write(std::ostream& out) const;
+ void read(const char *& data);
+ void write(std::ostream& out, bool optimize = false) const;
/**
* Debugging methods. There are two methods defined to help with
@@ -691,6 +696,8 @@ inline bool amount_t::operator==(const amount_t& amt) const {
}
inline amount_t amount_t::round() const {
+ if (! quantity)
+ throw_(amount_error, "Cannot round an uninitialized amount");
if (! has_commodity())
return *this;
return round(commodity().precision());
diff --git a/src/binary.cc b/src/binary.cc
index 0d4bfb80..d29f4d26 100644
--- a/src/binary.cc
+++ b/src/binary.cc
@@ -68,7 +68,7 @@ void read_binary_bool(std::istream& in, bool& num)
read_binary_guard(in, 0x2006);
}
-void read_binary_bool(char *& data, bool& num)
+void read_binary_bool(const char *& data, bool& num)
{
read_binary_guard(data, 0x2005);
unsigned char val = *((unsigned char *) data);
@@ -104,7 +104,7 @@ void read_binary_string(std::istream& in, string& str)
read_binary_guard(in, 0x3002);
}
-void read_binary_string(char *& data, string& str)
+void read_binary_string(const char *& data, string& str)
{
read_binary_guard(data, 0x3001);
@@ -127,7 +127,7 @@ void read_binary_string(char *& data, string& str)
read_binary_guard(data, 0x3002);
}
-void read_binary_string(char *& data, string * str)
+void read_binary_string(const char *& data, string * str)
{
read_binary_guard(data, 0x3001);
@@ -151,7 +151,7 @@ void read_binary_string(char *& data, string * str)
}
#if 0
-inline void read_binary_value(char *& data, value_t& val)
+inline void read_binary_value(const char *& data, value_t& val)
{
val.type = static_cast<value_t::type_t>(read_binary_long<int>(data));
@@ -176,7 +176,7 @@ inline void read_binary_value(char *& data, value_t& val)
}
}
-inline void read_binary_mask(char *& data, mask_t *& mask)
+inline void read_binary_mask(const char *& data, mask_t *& mask)
{
bool exclude;
read_binary_number(data, exclude);
@@ -187,7 +187,7 @@ inline void read_binary_mask(char *& data, mask_t *& mask)
mask->exclude = exclude;
}
-inline void read_binary_transaction(char *& data, transaction_t * xact)
+inline void read_binary_transaction(const char *& data, transaction_t * xact)
{
read_binary_number(data, xact->_date);
read_binary_number(data, xact->_date_eff);
@@ -230,7 +230,7 @@ inline void read_binary_transaction(char *& data, transaction_t * xact)
xact->data = NULL;
}
-inline void read_binary_entry_base(char *& data, entry_base_t * entry,
+inline void read_binary_entry_base(const char *& data, entry_base_t * entry,
transaction_t *& xact_pool, bool& finalize)
{
read_binary_long(data, entry->src_idx);
@@ -253,7 +253,7 @@ inline void read_binary_entry_base(char *& data, entry_base_t * entry,
}
}
-inline void read_binary_entry(char *& data, entry_t * entry,
+inline void read_binary_entry(const char *& data, entry_t * entry,
transaction_t *& xact_pool, bool& finalize)
{
entry->data =
@@ -266,7 +266,7 @@ inline void read_binary_entry(char *& data, entry_t * entry,
read_binary_string(data, &entry->payee);
}
-inline void read_binary_auto_entry(char *& data, auto_entry_t * entry,
+inline void read_binary_auto_entry(const char *& data, auto_entry_t * entry,
transaction_t *& xact_pool)
{
bool ignore;
@@ -277,7 +277,7 @@ inline void read_binary_auto_entry(char *& data, auto_entry_t * entry,
entry->predicate.parse(pred_str);
}
-inline void read_binary_period_entry(char *& data, period_entry_t * entry,
+inline void read_binary_period_entry(const char *& data, period_entry_t * entry,
transaction_t *& xact_pool, bool& finalize)
{
read_binary_entry_base(data, entry, xact_pool, finalize);
@@ -286,7 +286,7 @@ inline void read_binary_period_entry(char *& data, period_entry_t * entry,
entry->period.parse(stream);
}
-inline commodity_base_t * read_binary_commodity_base(char *& data)
+inline commodity_base_t * read_binary_commodity_base(const char *& data)
{
commodity_base_t * commodity = new commodity_base_t;
*base_commodities_next++ = commodity;
@@ -300,7 +300,7 @@ inline commodity_base_t * read_binary_commodity_base(char *& data)
return commodity;
}
-inline void read_binary_commodity_base_extra(char *& data,
+inline void read_binary_commodity_base_extra(const char *& data,
commodity_t::ident_t ident)
{
commodity_base_t * commodity = base_commodities[ident];
@@ -339,7 +339,7 @@ inline void read_binary_commodity_base_extra(char *& data,
}
}
-inline commodity_t * read_binary_commodity(char *& data)
+inline commodity_t * read_binary_commodity(const char *& data)
{
commodity_t * commodity = new commodity_t;
*commodities_next++ = commodity;
@@ -353,7 +353,7 @@ inline commodity_t * read_binary_commodity(char *& data)
return commodity;
}
-inline commodity_t * read_binary_commodity_annotated(char *& data)
+inline commodity_t * read_binary_commodity_annotated(const char *& data)
{
annotated_commodity_t * commodity = new annotated_commodity_t;
*commodities_next++ = commodity;
@@ -381,7 +381,7 @@ inline commodity_t * read_binary_commodity_annotated(char *& data)
}
inline
-account_t * read_binary_account(char *& data, journal_t * journal,
+account_t * read_binary_account(const char *& data, journal_t * journal,
account_t * master = NULL)
{
account_t * acct = new account_t(NULL);
diff --git a/src/binary.h b/src/binary.h
index 194c675e..5d699f7b 100644
--- a/src/binary.h
+++ b/src/binary.h
@@ -55,7 +55,7 @@ inline void read_binary_number_nocheck(std::istream& in, T& num) {
}
template <typename T>
-inline void read_binary_number_nocheck(char *& data, T& num) {
+inline void read_binary_number_nocheck(const char *& data, T& num) {
num = *((T *) data);
data += sizeof(T);
}
@@ -68,7 +68,7 @@ inline T read_binary_number_nocheck(std::istream& in) {
}
template <typename T>
-inline T read_binary_number_nocheck(char *& data) {
+inline T read_binary_number_nocheck(const char *& data) {
T num;
read_binary_number_nocheck(data, num);
return num;
@@ -90,7 +90,7 @@ inline void read_binary_number(std::istream& in, T& num) {
}
template <typename T>
-inline void read_binary_number(char *& data, T& num) {
+inline void read_binary_number(const char *& data, T& num) {
read_binary_guard(data, 0x2003);
num = *((T *) data);
data += sizeof(T);
@@ -105,14 +105,14 @@ inline T read_binary_number(std::istream& in) {
}
template <typename T>
-inline T read_binary_number(char *& data) {
+inline T read_binary_number(const char *& data) {
T num;
read_binary_number(data, num);
return num;
}
void read_binary_bool(std::istream& in, bool& num);
-void read_binary_bool(char *& data, bool& num);
+void read_binary_bool(const char *& data, bool& num);
inline bool read_binary_bool(std::istream& in) {
bool num;
@@ -120,7 +120,7 @@ inline bool read_binary_bool(std::istream& in) {
return num;
}
-inline bool read_binary_bool(char *& data) {
+inline bool read_binary_bool(const char *& data) {
bool num;
read_binary_bool(data, num);
return num;
@@ -156,7 +156,7 @@ void read_binary_long(std::istream& in, T& num)
}
template <typename T>
-void read_binary_long(char *& data, T& num)
+void read_binary_long(const char *& data, T& num)
{
read_binary_guard(data, 0x2001);
@@ -192,15 +192,15 @@ inline T read_binary_long(std::istream& in) {
}
template <typename T>
-inline T read_binary_long(char *& data) {
+inline T read_binary_long(const char *& data) {
T num;
read_binary_long(data, num);
return num;
}
void read_binary_string(std::istream& in, string& str);
-void read_binary_string(char *& data, string& str);
-void read_binary_string(char *& data, string * str);
+void read_binary_string(const char *& data, string& str);
+void read_binary_string(const char *& data, string * str);
inline string read_binary_string(std::istream& in) {
string temp;
@@ -208,7 +208,7 @@ inline string read_binary_string(std::istream& in) {
return temp;
}
-inline string read_binary_string(char *& data) {
+inline string read_binary_string(const char *& data) {
string temp;
read_binary_string(data, temp);
return temp;