added asserts to, and proof-read, amount.cc
This commit is contained in:
parent
52c7d928c7
commit
ab86cd8c37
4 changed files with 267 additions and 263 deletions
454
amount.cc
454
amount.cc
|
|
@ -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,187 +396,6 @@ amount_t& amount_t::operator-=(const amount_t& amt)
|
|||
return *this;
|
||||
}
|
||||
|
||||
// unary negation
|
||||
amount_t& amount_t::negate()
|
||||
{
|
||||
if (quantity) {
|
||||
_dup();
|
||||
mpz_ui_sub(MPZ(quantity), 0, MPZ(quantity));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// integer comparisons
|
||||
template <typename T>
|
||||
static inline void parse_num(amount_t& amt, T num) {
|
||||
std::string str;
|
||||
{ std::ostringstream strstr(str);
|
||||
strstr << num;
|
||||
}
|
||||
{ std::istringstream strstr(str);
|
||||
amt.parse(strstr);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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 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;
|
||||
}
|
||||
}
|
||||
|
||||
// comparisons between amounts
|
||||
#define DEF_CMP_OPERATOR(OP) \
|
||||
bool amount_t::operator OP(const amount_t& amt) const \
|
||||
{ \
|
||||
if (! quantity) \
|
||||
return amt > 0; \
|
||||
if (! amt.quantity) \
|
||||
return *this < 0; \
|
||||
\
|
||||
if (commodity != amt.commodity) \
|
||||
throw amount_error("Comparing amounts with different commodities"); \
|
||||
\
|
||||
if (quantity->prec == amt.quantity->prec) { \
|
||||
return mpz_cmp(MPZ(quantity), MPZ(amt.quantity)) OP 0; \
|
||||
} \
|
||||
else if (quantity->prec < amt.quantity->prec) { \
|
||||
amount_t temp = *this; \
|
||||
temp._resize(amt.quantity->prec); \
|
||||
return mpz_cmp(MPZ(temp.quantity), MPZ(amt.quantity)) OP 0; \
|
||||
} \
|
||||
else { \
|
||||
amount_t temp = amt; \
|
||||
temp._resize(quantity->prec); \
|
||||
return mpz_cmp(MPZ(quantity), MPZ(temp.quantity)) OP 0; \
|
||||
} \
|
||||
}
|
||||
|
||||
DEF_CMP_OPERATOR(<)
|
||||
DEF_CMP_OPERATOR(<=)
|
||||
DEF_CMP_OPERATOR(>)
|
||||
DEF_CMP_OPERATOR(>=)
|
||||
DEF_CMP_OPERATOR(==)
|
||||
|
||||
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 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
amount_t amount_t::value(const std::time_t moment) const
|
||||
{
|
||||
if (quantity && ! (commodity->flags & COMMODITY_STYLE_NOMARKET))
|
||||
if (amount_t amt = commodity->value(moment))
|
||||
return (amt * *this).round(commodity->precision);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
amount_t& amount_t::operator*=(const amount_t& amt)
|
||||
{
|
||||
if (! amt.quantity || ! quantity)
|
||||
|
|
@ -611,18 +440,135 @@ amount_t& amount_t::operator/=(const amount_t& amt)
|
|||
return *this;
|
||||
}
|
||||
|
||||
// unary negation
|
||||
amount_t& amount_t::negate()
|
||||
{
|
||||
if (quantity) {
|
||||
_dup();
|
||||
mpz_neg(MPZ(quantity), MPZ(quantity));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// integer comparisons
|
||||
template <typename T>
|
||||
static inline void parse_num(amount_t& amt, T num) {
|
||||
std::string str;
|
||||
{ std::ostringstream strstr(str);
|
||||
strstr << num;
|
||||
}
|
||||
{ std::istringstream strstr(str);
|
||||
amt.parse(strstr);
|
||||
}
|
||||
}
|
||||
|
||||
#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; \
|
||||
} \
|
||||
}
|
||||
|
||||
AMOUNT_CMP_INT(<)
|
||||
AMOUNT_CMP_INT(<=)
|
||||
AMOUNT_CMP_INT(>)
|
||||
AMOUNT_CMP_INT(>=)
|
||||
AMOUNT_CMP_INT(==)
|
||||
|
||||
#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; \
|
||||
} \
|
||||
}
|
||||
|
||||
AMOUNT_CMP_UINT(<)
|
||||
AMOUNT_CMP_UINT(<=)
|
||||
AMOUNT_CMP_UINT(>)
|
||||
AMOUNT_CMP_UINT(>=)
|
||||
AMOUNT_CMP_UINT(==)
|
||||
|
||||
// comparisons between amounts
|
||||
#define AMOUNT_CMP_AMOUNT(OP) \
|
||||
bool amount_t::operator OP(const amount_t& amt) const \
|
||||
{ \
|
||||
if (! quantity) \
|
||||
return amt > 0; \
|
||||
if (! amt.quantity) \
|
||||
return *this < 0; \
|
||||
\
|
||||
if (commodity != amt.commodity) \
|
||||
throw amount_error("Comparing amounts with different commodities"); \
|
||||
\
|
||||
if (quantity->prec == amt.quantity->prec) { \
|
||||
return mpz_cmp(MPZ(quantity), MPZ(amt.quantity)) OP 0; \
|
||||
} \
|
||||
else if (quantity->prec < amt.quantity->prec) { \
|
||||
amount_t temp = *this; \
|
||||
temp._resize(amt.quantity->prec); \
|
||||
return mpz_cmp(MPZ(temp.quantity), MPZ(amt.quantity)) OP 0; \
|
||||
} \
|
||||
else { \
|
||||
amount_t temp = amt; \
|
||||
temp._resize(quantity->prec); \
|
||||
return mpz_cmp(MPZ(quantity), MPZ(temp.quantity)) OP 0; \
|
||||
} \
|
||||
}
|
||||
|
||||
AMOUNT_CMP_AMOUNT(<)
|
||||
AMOUNT_CMP_AMOUNT(<=)
|
||||
AMOUNT_CMP_AMOUNT(>)
|
||||
AMOUNT_CMP_AMOUNT(>=)
|
||||
AMOUNT_CMP_AMOUNT(==)
|
||||
|
||||
amount_t::operator bool() const
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
amount_t amount_t::value(const std::time_t moment) const
|
||||
{
|
||||
if (quantity && ! (commodity->flags & COMMODITY_STYLE_NOMARKET))
|
||||
if (amount_t amt = commodity->value(moment))
|
||||
return (amt * *this).round(commodity->precision);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
amount_t amount_t::round(unsigned int prec) const
|
||||
{
|
||||
if (! quantity || quantity->prec <= prec) {
|
||||
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;
|
||||
}
|
||||
|
||||
amount_t temp = *this;
|
||||
temp._dup();
|
||||
|
||||
mpz_round(MPZ(temp.quantity), MPZ(temp.quantity), temp.quantity->prec, prec);
|
||||
temp.quantity->prec = prec;
|
||||
|
||||
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++;
|
||||
while (*p) {
|
||||
if (*p == ',' || *p == '.')
|
||||
p++;
|
||||
*t++ = *p++;
|
||||
}
|
||||
*t = '\0';
|
||||
|
||||
mpz_set_str(MPZ(quantity), buf, 10);
|
||||
|
||||
delete[] buf;
|
||||
} else {
|
||||
mpz_set_str(MPZ(quantity), quant.c_str(), 10);
|
||||
}
|
||||
*t = '\0';
|
||||
|
||||
mpz_set_str(MPZ(quantity), buf, 10);
|
||||
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
|
|||
68
amount.h
68
amount.h
|
|
@ -4,6 +4,7 @@
|
|||
#include <map>
|
||||
#include <string>
|
||||
#include <ctime>
|
||||
#include <cctype>
|
||||
#include <iostream>
|
||||
|
||||
#include "debug.h"
|
||||
|
|
@ -21,10 +22,14 @@ class amount_t
|
|||
void _resize(unsigned int prec);
|
||||
|
||||
void _clear() {
|
||||
if (quantity)
|
||||
if (quantity) {
|
||||
assert(commodity);
|
||||
_release();
|
||||
quantity = NULL;
|
||||
commodity = NULL;
|
||||
quantity = NULL;
|
||||
commodity = NULL;
|
||||
} else {
|
||||
assert(! commodity);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
@ -33,19 +38,10 @@ class amount_t
|
|||
bigint_t * quantity;
|
||||
commodity_t * commodity;
|
||||
|
||||
bool valid() const {
|
||||
if (quantity)
|
||||
return commodity != NULL;
|
||||
else
|
||||
return commodity == NULL;
|
||||
}
|
||||
|
||||
// constructors
|
||||
amount_t(commodity_t * _commodity = NULL)
|
||||
: quantity(NULL), commodity(_commodity) {
|
||||
amount_t() : quantity(NULL), commodity(NULL) {
|
||||
DEBUG_PRINT("ledger.memory.ctors", "ctor amount_t");
|
||||
}
|
||||
|
||||
amount_t(const amount_t& amt) : quantity(NULL) {
|
||||
DEBUG_PRINT("ledger.memory.ctors", "ctor amount_t");
|
||||
if (amt.quantity)
|
||||
|
|
@ -86,10 +82,10 @@ class amount_t
|
|||
amount_t round(unsigned int prec) const;
|
||||
|
||||
// in-place arithmetic
|
||||
amount_t& operator*=(const amount_t& amt);
|
||||
amount_t& operator/=(const amount_t& amt);
|
||||
amount_t& operator+=(const amount_t& amt);
|
||||
amount_t& operator-=(const amount_t& amt);
|
||||
amount_t& operator*=(const amount_t& amt);
|
||||
amount_t& operator/=(const amount_t& amt);
|
||||
|
||||
// simple arithmetic
|
||||
amount_t operator*(const amount_t& amt) const {
|
||||
|
|
@ -132,6 +128,10 @@ class amount_t
|
|||
bool operator<=(const int num) const;
|
||||
bool operator>(const int num) const;
|
||||
bool operator>=(const int num) const;
|
||||
bool operator==(const int num) const;
|
||||
bool operator!=(const int num) const {
|
||||
return ! (*this == num);
|
||||
}
|
||||
|
||||
bool operator<(const unsigned int num) const;
|
||||
bool operator<=(const unsigned int num) const;
|
||||
|
|
@ -167,6 +167,8 @@ class amount_t
|
|||
void write_quantity(std::ostream& out) const;
|
||||
void read_quantity(std::istream& in);
|
||||
|
||||
bool valid() const;
|
||||
|
||||
friend std::istream& operator>>(std::istream& in, amount_t& amt);
|
||||
};
|
||||
|
||||
|
|
@ -229,19 +231,23 @@ class commodity_t
|
|||
// If set, this global function pointer is called to determine
|
||||
// whether prices have been updated in the meanwhile.
|
||||
|
||||
static updater_t * updater;
|
||||
static updater_t * updater;
|
||||
|
||||
// This map remembers all commodities that have been
|
||||
// defined thus far.
|
||||
// This map remembers all commodities that have been defined.
|
||||
|
||||
static commodities_map commodities;
|
||||
static commodity_t * null_commodity;
|
||||
|
||||
static void add_commodity(commodity_t * commodity,
|
||||
const std::string symbol = "") {
|
||||
commodities.insert(commodities_pair((symbol.empty() ?
|
||||
commodity->symbol : symbol),
|
||||
commodity));
|
||||
// The argument "symbol" is useful for creating a symbol alias to
|
||||
// an underlying commodity type; it is used by the Gnucash parser
|
||||
// to link "USD" to "$".
|
||||
std::pair<commodities_map::iterator, bool> result
|
||||
= commodities.insert(commodities_pair((symbol.empty() ?
|
||||
commodity->symbol : symbol),
|
||||
commodity));
|
||||
assert(result.second);
|
||||
}
|
||||
static bool remove_commodity(commodity_t * commodity) {
|
||||
commodities_map::size_type n = commodities.erase(commodity->symbol);
|
||||
|
|
@ -274,9 +280,7 @@ class commodity_t
|
|||
}
|
||||
}
|
||||
|
||||
void add_price(const std::time_t date, const amount_t& price) {
|
||||
history.insert(history_pair(date, price));
|
||||
}
|
||||
void add_price(const std::time_t date, const amount_t& price);
|
||||
bool remove_price(const std::time_t date) {
|
||||
history_map::size_type n = history.erase(date);
|
||||
return n > 0;
|
||||
|
|
@ -287,6 +291,22 @@ class commodity_t
|
|||
}
|
||||
|
||||
amount_t value(const std::time_t moment = std::time(NULL));
|
||||
|
||||
bool valid() const {
|
||||
if (symbol.empty() && this != null_commodity)
|
||||
return false;
|
||||
|
||||
if (precision > 16)
|
||||
return false;
|
||||
|
||||
if (flags & ~0x1f)
|
||||
return false;
|
||||
|
||||
if (! conversion.valid())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ledger
|
||||
|
|
|
|||
2
debug.h
2
debug.h
|
|
@ -8,7 +8,7 @@
|
|||
#define NO_SEATBELT 0
|
||||
|
||||
#ifndef DEBUG_LEVEL
|
||||
#define DEBUG_LEVEL RELEASE
|
||||
#define DEBUG_LEVEL NO_SEATBELT
|
||||
#endif
|
||||
|
||||
#if DEBUG_LEVEL >= RELEASE
|
||||
|
|
|
|||
|
|
@ -253,6 +253,12 @@ bool journal_t::valid() const
|
|||
if (! (*i)->valid())
|
||||
return false;
|
||||
|
||||
for (commodities_map::const_iterator i = commodity_t::commodities.begin();
|
||||
i != commodity_t::commodities.end();
|
||||
i++)
|
||||
if (! (*i).second->valid())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue