diff options
author | John Wiegley <johnw@newartisans.com> | 2004-08-25 17:34:23 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2004-08-25 17:34:23 -0400 |
commit | ab86cd8c3743ba5ae5c2ef2f7e20c51b870bb7e5 (patch) | |
tree | 1ecbd6da2f73e85960d3d7a560e172b5e15e0913 /amount.cc | |
parent | 52c7d928c7f39c7c3f4cccaf38560687bfff4b9f (diff) | |
download | fork-ledger-ab86cd8c3743ba5ae5c2ef2f7e20c51b870bb7e5.tar.gz fork-ledger-ab86cd8c3743ba5ae5c2ef2f7e20c51b870bb7e5.tar.bz2 fork-ledger-ab86cd8c3743ba5ae5c2ef2f7e20c51b870bb7e5.zip |
added asserts to, and proof-read, amount.cc
Diffstat (limited to 'amount.cc')
-rw-r--r-- | amount.cc | 398 |
1 files changed, 188 insertions, 210 deletions
@@ -1,11 +1,11 @@ #include "ledger.h" +#include "amount.h" #include "binary.h" #include "error.h" #include "util.h" -#include "debug.h" -#include <deque> #include <sstream> +#include <cstring> #include "gmp.h" @@ -47,20 +47,20 @@ unsigned int sizeof_bigint_t() { #define MPZ(x) ((x)->val) -static mpz_t temp; -static mpz_t divisor; -static mpz_t true_value; +static mpz_t temp; +static mpz_t divisor; +static amount_t::bigint_t true_value; -commodity_t::updater_t * commodity_t::updater; -commodities_map commodity_t::commodities; -commodity_t * commodity_t::null_commodity; +commodity_t::updater_t * commodity_t::updater = NULL; +commodities_map commodity_t::commodities; +commodity_t * commodity_t::null_commodity; void initialize_amounts() { mpz_init(temp); mpz_init(divisor); - mpz_init(true_value); - mpz_set_ui(true_value, 1); + + mpz_set_ui(true_value.val, 1); commodity_t::updater = NULL; commodity_t::null_commodity = commodity_t::find_commodity("", true); @@ -68,12 +68,15 @@ void initialize_amounts() void shutdown_amounts() { - mpz_clear(true_value); mpz_clear(divisor); mpz_clear(temp); - if (commodity_t::updater) + true_value.ref--; + + if (commodity_t::updater) { delete commodity_t::updater; + commodity_t::updater = NULL; + } for (commodities_map::iterator i = commodity_t::commodities.begin(); i != commodity_t::commodities.end(); @@ -121,20 +124,21 @@ static void mpz_round(mpz_t out, mpz_t value, int value_prec, int round_prec) mpz_sub(out, value, remainder); } } + mpz_clear(quotient); + mpz_clear(remainder); // chop off the rounded bits mpz_ui_pow_ui(divisor, 10, value_prec - round_prec); mpz_tdiv_q(out, out, divisor); - - mpz_clear(quotient); - mpz_clear(remainder); } amount_t::amount_t(const bool value) { DEBUG_PRINT("ledger.memory.ctors", "ctor amount_t"); + if (value) { - quantity = new bigint_t(true_value); + quantity = &true_value; + quantity->ref++; commodity = commodity_t::null_commodity; } else { quantity = NULL; @@ -145,6 +149,7 @@ amount_t::amount_t(const bool value) amount_t::amount_t(const int value) { DEBUG_PRINT("ledger.memory.ctors", "ctor amount_t"); + if (value != 0) { quantity = new bigint_t; mpz_set_si(MPZ(quantity), value); @@ -158,6 +163,7 @@ amount_t::amount_t(const int value) amount_t::amount_t(const unsigned int value) { DEBUG_PRINT("ledger.memory.ctors", "ctor amount_t"); + if (value != 0) { quantity = new bigint_t; mpz_set_ui(MPZ(quantity), value); @@ -171,6 +177,7 @@ amount_t::amount_t(const unsigned int value) amount_t::amount_t(const double value) { DEBUG_PRINT("ledger.memory.ctors", "ctor amount_t"); + if (value != 0.0) { quantity = new bigint_t; mpz_set_d(MPZ(quantity), value); @@ -233,7 +240,7 @@ amount_t& amount_t::operator=(const std::string& value) amount_t& amount_t::operator=(const char * value) { - std::string valstr(value); + std::string valstr(value); std::istringstream str(valstr); parse(str); return *this; @@ -257,8 +264,10 @@ amount_t& amount_t::operator=(const bool value) _clear(); } else { commodity = commodity_t::null_commodity; - _init(); - mpz_set(MPZ(quantity), true_value); + if (quantity) + _release(); + quantity = &true_value; + quantity->ref++; } return *this; } @@ -306,6 +315,8 @@ amount_t& amount_t::operator=(const double value) void amount_t::_resize(unsigned int prec) { + assert(prec < 256); + if (! quantity || prec == quantity->prec) return; @@ -329,8 +340,7 @@ amount_t& amount_t::operator+=(const amount_t& amt) return *this; if (! quantity) { - quantity = new bigint_t(*amt.quantity); - commodity = amt.commodity; + _copy(amt); return *this; } @@ -361,8 +371,8 @@ amount_t& amount_t::operator-=(const amount_t& amt) if (! quantity) { quantity = new bigint_t(*amt.quantity); - mpz_neg(MPZ(quantity), MPZ(quantity)); commodity = amt.commodity; + mpz_neg(MPZ(quantity), MPZ(quantity)); return *this; } @@ -386,12 +396,56 @@ amount_t& amount_t::operator-=(const amount_t& amt) return *this; } +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)); + quantity->prec += amt.quantity->prec; + + if (quantity->prec > commodity->precision + 6U) { + mpz_round(MPZ(quantity), MPZ(quantity), + quantity->prec, commodity->precision + 6U); + quantity->prec = commodity->precision + 6U; + } + + return *this; +} + +amount_t& amount_t::operator/=(const amount_t& amt) +{ + if (! quantity) + return *this; + 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.quantity->prec + 6); + mpz_mul(MPZ(quantity), MPZ(quantity), divisor); + mpz_tdiv_q(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity)); + quantity->prec += 6; + + if (quantity->prec > commodity->precision + 6U) { + mpz_round(MPZ(quantity), MPZ(quantity), + quantity->prec, commodity->precision + 6U); + quantity->prec = commodity->precision + 6U; + } + + return *this; +} + // unary negation amount_t& amount_t::negate() { if (quantity) { _dup(); - mpz_ui_sub(MPZ(quantity), 0, MPZ(quantity)); + mpz_neg(MPZ(quantity), MPZ(quantity)); } return *this; } @@ -408,107 +462,44 @@ static inline void parse_num(amount_t& amt, T num) { } } -bool amount_t::operator<(const int num) const -{ - if (num == 0) { - return quantity ? mpz_sgn(MPZ(quantity)) < 0 : false; - } else { - amount_t amt; - parse_num(amt, num); - return *this < amt; - } +#define AMOUNT_CMP_INT(OP) \ +bool amount_t::operator OP (const int num) const \ +{ \ + if (num == 0) { \ + return quantity ? mpz_sgn(MPZ(quantity)) OP 0 : false; \ + } else { \ + amount_t amt; \ + parse_num(amt, num); \ + return *this OP amt; \ + } \ } -bool amount_t::operator<=(const int num) const -{ - if (num == 0) { - return quantity ? mpz_sgn(MPZ(quantity)) <= 0 : true; - } else { - amount_t amt; - parse_num(amt, num); - return *this <= amt; - } -} - -bool amount_t::operator>(const int num) const -{ - if (num == 0) { - return quantity ? mpz_sgn(MPZ(quantity)) > 0 : false; - } else { - amount_t amt; - parse_num(amt, num); - return *this > amt; - } -} +AMOUNT_CMP_INT(<) +AMOUNT_CMP_INT(<=) +AMOUNT_CMP_INT(>) +AMOUNT_CMP_INT(>=) +AMOUNT_CMP_INT(==) -bool amount_t::operator>=(const int num) const -{ - if (num == 0) { - return quantity ? mpz_sgn(MPZ(quantity)) >= 0 : true; - } else { - amount_t amt; - parse_num(amt, num); - return *this >= amt; - } +#define AMOUNT_CMP_UINT(OP) \ +bool amount_t::operator OP (const unsigned int num) const \ +{ \ + if (num == 0) { \ + return quantity ? mpz_sgn(MPZ(quantity)) OP 0 : false; \ + } else { \ + amount_t amt; \ + parse_num(amt, num); \ + return *this OP amt; \ + } \ } -bool amount_t::operator<(const unsigned int num) const -{ - if (num == 0) { - return quantity ? mpz_sgn(MPZ(quantity)) < 0 : false; - } else { - amount_t amt; - parse_num(amt, num); - return *this < amt; - } -} - -bool amount_t::operator<=(const unsigned int num) const -{ - if (num == 0) { - return quantity ? mpz_sgn(MPZ(quantity)) <= 0 : true; - } else { - amount_t amt; - parse_num(amt, num); - return *this <= amt; - } -} - -bool amount_t::operator>(const unsigned int num) const -{ - if (num == 0) { - return quantity ? mpz_sgn(MPZ(quantity)) > 0 : false; - } else { - amount_t amt; - parse_num(amt, num); - return *this > amt; - } -} - -bool amount_t::operator>=(const unsigned int num) const -{ - if (num == 0) { - return quantity ? mpz_sgn(MPZ(quantity)) >= 0 : true; - } else { - amount_t amt; - parse_num(amt, num); - return *this >= amt; - } -} - -bool amount_t::operator==(const unsigned int num) const -{ - if (num == 0) { - return quantity ? mpz_sgn(MPZ(quantity)) == 0 : true; - } else { - amount_t amt; - parse_num(amt, num); - return *this == amt; - } -} +AMOUNT_CMP_UINT(<) +AMOUNT_CMP_UINT(<=) +AMOUNT_CMP_UINT(>) +AMOUNT_CMP_UINT(>=) +AMOUNT_CMP_UINT(==) // comparisons between amounts -#define DEF_CMP_OPERATOR(OP) \ +#define AMOUNT_CMP_AMOUNT(OP) \ bool amount_t::operator OP(const amount_t& amt) const \ { \ if (! quantity) \ @@ -534,27 +525,26 @@ bool amount_t::operator OP(const amount_t& amt) const \ } \ } -DEF_CMP_OPERATOR(<) -DEF_CMP_OPERATOR(<=) -DEF_CMP_OPERATOR(>) -DEF_CMP_OPERATOR(>=) -DEF_CMP_OPERATOR(==) +AMOUNT_CMP_AMOUNT(<) +AMOUNT_CMP_AMOUNT(<=) +AMOUNT_CMP_AMOUNT(>) +AMOUNT_CMP_AMOUNT(>=) +AMOUNT_CMP_AMOUNT(==) amount_t::operator bool() const { - if (quantity) { - if (quantity->prec <= commodity->precision) { - return mpz_sgn(MPZ(quantity)) != 0; - } else { - assert(commodity); - mpz_set(temp, MPZ(quantity)); - mpz_ui_pow_ui(divisor, 10, quantity->prec - commodity->precision); - mpz_tdiv_q(temp, temp, divisor); - bool zero = mpz_sgn(temp) == 0; - return ! zero; - } - } else { + if (! quantity) return false; + + if (quantity->prec <= commodity->precision) { + return mpz_sgn(MPZ(quantity)) != 0; + } else { + assert(commodity); + mpz_set(temp, MPZ(quantity)); + mpz_ui_pow_ui(divisor, 10, quantity->prec - commodity->precision); + mpz_tdiv_q(temp, temp, divisor); + bool zero = mpz_sgn(temp) == 0; + return ! zero; } } @@ -567,62 +557,18 @@ amount_t amount_t::value(const std::time_t moment) const return *this; } -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)); - quantity->prec += amt.quantity->prec; - - if (quantity->prec > commodity->precision + 6U) { - mpz_round(MPZ(quantity), MPZ(quantity), - quantity->prec, commodity->precision + 6U); - quantity->prec = commodity->precision + 6U; - } - - return *this; -} - -amount_t& amount_t::operator/=(const amount_t& amt) +amount_t amount_t::round(unsigned int prec) const { - if (! quantity) + if (! quantity || quantity->prec <= prec) return *this; - if (! amt.quantity) - throw amount_error("Divide by zero"); - _dup(); + amount_t temp = *this; + temp._dup(); - // Increase the value's precision, to capture fractional parts after - // the divide. - mpz_ui_pow_ui(divisor, 10, amt.quantity->prec + 6); - mpz_mul(MPZ(quantity), MPZ(quantity), divisor); - mpz_tdiv_q(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity)); - quantity->prec += 6; + mpz_round(MPZ(temp.quantity), MPZ(temp.quantity), temp.quantity->prec, prec); + temp.quantity->prec = prec; - if (quantity->prec > commodity->precision + 6U) { - mpz_round(MPZ(quantity), MPZ(quantity), - quantity->prec, commodity->precision + 6U); - quantity->prec = commodity->precision + 6U; - } - - return *this; -} - -amount_t amount_t::round(unsigned int prec) const -{ - if (! quantity || quantity->prec <= prec) { - return *this; - } else { - amount_t temp = *this; - temp._dup(); - mpz_round(MPZ(temp.quantity), MPZ(temp.quantity), - temp.quantity->prec, prec); - temp.quantity->prec = prec; - return temp; - } + return temp; } std::ostream& operator<<(std::ostream& _out, const amount_t& amt) @@ -827,52 +773,55 @@ void amount_t::parse(std::istream& in) std::string::size_type last_comma = quant.rfind(','); std::string::size_type last_period = quant.rfind('.'); - unsigned int precision = 0; - if (last_comma != std::string::npos && last_period != std::string::npos) { flags |= COMMODITY_STYLE_THOUSANDS; if (last_comma > last_period) { flags |= COMMODITY_STYLE_EUROPEAN; - precision = quant.length() - last_comma - 1; + quantity->prec = quant.length() - last_comma - 1; } else { - precision = quant.length() - last_period - 1; + quantity->prec = quant.length() - last_period - 1; } } else if (last_comma != std::string::npos) { flags |= COMMODITY_STYLE_EUROPEAN; - precision = quant.length() - last_comma - 1; + quantity->prec = quant.length() - last_comma - 1; } else if (last_period != std::string::npos) { - precision = quant.length() - last_period - 1; + quantity->prec = quant.length() - last_period - 1; + } + else { + quantity->prec = 0; } - - quantity->prec = precision; // Create the commodity if has not already been seen. commodity = commodity_t::find_commodity(symbol, true); commodity->flags |= flags; - if (precision > commodity->precision) - commodity->precision = precision; + if (quantity->prec > commodity->precision) + commodity->precision = quantity->prec; - // The number is specified as the user desires, with the commodity - // flags telling how to parse it. + // Now we have the final number. Remove commas and periods, if + // necessary. - int len = quant.length(); - char * buf = new char[len + 1]; + if (last_comma != std::string::npos || last_period != std::string::npos) { + int len = quant.length(); + char * buf = new char[len + 1]; - const char * p = quant.c_str(); - char * t = buf; + const char * p = quant.c_str(); + char * t = buf; - while (*p) { - if (*p == ',' || *p == '.') - p++; - *t++ = *p++; - } - *t = '\0'; + while (*p) { + if (*p == ',' || *p == '.') + p++; + *t++ = *p++; + } + *t = '\0'; - mpz_set_str(MPZ(quantity), buf, 10); + mpz_set_str(MPZ(quantity), buf, 10); - delete[] buf; + delete[] buf; + } else { + mpz_set_str(MPZ(quantity), quant.c_str(), 10); + } } void amount_t::parse(const std::string& str) @@ -943,7 +892,8 @@ void amount_t::read_quantity(std::istream& in) unsigned short len; in.read((char *)&len, sizeof(len)); in.read(buf, len); - mpz_import(MPZ(quantity), len / sizeof(short), 1, sizeof(short), 0, 0, buf); + mpz_import(MPZ(quantity), len / sizeof(short), 1, sizeof(short), + 0, 0, buf); char negative; in.read(&negative, sizeof(negative)); @@ -961,6 +911,34 @@ void amount_t::read_quantity(std::istream& in) } } +bool amount_t::valid() const +{ + if (quantity) { + if (! commodity) + return false; + + if (quantity->ref == 0) + return false; + } + else if (commodity) { + return false; + } + + return true; +} + + +void commodity_t::add_price(const std::time_t date, const amount_t& price) +{ + history_map::const_iterator i = history.find(date); + if (i != history.end()) { + (*i).second = price; + } else { + std::pair<history_map::iterator, bool> result + = history.insert(history_pair(date, price)); + assert(result.second); + } +} commodity_t * commodity_t::find_commodity(const std::string& symbol, bool auto_create) |