diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/TODO | 5 | ||||
-rw-r--r-- | src/amount.cc | 103 | ||||
-rw-r--r-- | src/amount.h | 19 | ||||
-rw-r--r-- | src/binary.cc | 30 | ||||
-rw-r--r-- | src/binary.h | 22 |
5 files changed, 96 insertions, 83 deletions
@@ -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; |