summaryrefslogtreecommitdiff
path: root/src/amount.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/amount.cc')
-rw-r--r--src/amount.cc99
1 files changed, 50 insertions, 49 deletions
diff --git a/src/amount.cc b/src/amount.cc
index 85afc3d8..5e933215 100644
--- a/src/amount.cc
+++ b/src/amount.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2010, John Wiegley. All rights reserved.
+ * Copyright (c) 2003-2012, John Wiegley. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -63,16 +63,16 @@ struct amount_t::bigint_t : public supports_flags<>
#define MP(bigint) ((bigint)->val)
bigint_t() : prec(0), refc(1) {
- TRACE_CTOR(bigint_t, "");
mpq_init(val);
+ TRACE_CTOR(bigint_t, "");
}
bigint_t(const bigint_t& other)
: supports_flags<>(static_cast<uint_least8_t>
(other.flags() & ~BIGINT_BULK_ALLOC)),
prec(other.prec), refc(1) {
- TRACE_CTOR(bigint_t, "copy");
mpq_init(val);
mpq_set(val, other.val);
+ TRACE_CTOR(bigint_t, "copy");
}
~bigint_t() {
TRACE_DTOR(bigint_t);
@@ -120,11 +120,13 @@ namespace {
{
char * buf = NULL;
try {
+#if defined(DEBUG_ON)
IF_DEBUG("amount.convert") {
char * tbuf = mpq_get_str(NULL, 10, quant);
DEBUG("amount.convert", "Rational to convert = " << tbuf);
std::free(tbuf);
}
+#endif
// Convert the rational number to a floating-point, extending the
// floating-point to a large enough size to get a precise answer.
@@ -347,24 +349,24 @@ void amount_t::_release()
amount_t::amount_t(const double val) : commodity_(NULL)
{
- TRACE_CTOR(amount_t, "const double");
quantity = new bigint_t;
mpq_set_d(MP(quantity), val);
quantity->prec = extend_by_digits; // an approximation
+ TRACE_CTOR(amount_t, "const double");
}
amount_t::amount_t(const unsigned long val) : commodity_(NULL)
{
- TRACE_CTOR(amount_t, "const unsigned long");
quantity = new bigint_t;
mpq_set_ui(MP(quantity), val, 1);
+ TRACE_CTOR(amount_t, "const unsigned long");
}
amount_t::amount_t(const long val) : commodity_(NULL)
{
- TRACE_CTOR(amount_t, "const long");
quantity = new bigint_t;
mpq_set_si(MP(quantity), val, 1);
+ TRACE_CTOR(amount_t, "const long");
}
@@ -393,11 +395,11 @@ int amount_t::compare(const amount_t& amt) const
throw_(amount_error, _("Cannot compare two uninitialized amounts"));
}
- if (has_commodity() && amt.has_commodity() &&
- commodity() != amt.commodity())
+ if (has_commodity() && amt.has_commodity() && commodity() != amt.commodity()) {
throw_(amount_error,
- _("Cannot compare amounts with different commodities: %1 and %2")
- << commodity().symbol() << amt.commodity().symbol());
+ _("Cannot compare amounts with different commodities: '%1' and '%2'")
+ << commodity() << amt.commodity());
+ }
return mpq_cmp(MP(quantity), MP(amt.quantity));
}
@@ -428,12 +430,11 @@ amount_t& amount_t::operator+=(const amount_t& amt)
throw_(amount_error, _("Cannot add two uninitialized amounts"));
}
- if (has_commodity() && amt.has_commodity() &&
- commodity() != amt.commodity())
+ if (has_commodity() && amt.has_commodity() && commodity() != amt.commodity()) {
throw_(amount_error,
- _("Adding amounts with different commodities: %1 != %2")
- << (has_commodity() ? commodity().symbol() : _("NONE"))
- << (amt.has_commodity() ? amt.commodity().symbol() : _("NONE")));
+ _("Adding amounts with different commodities: '%1' != '%2'")
+ << commodity() << amt.commodity());
+ }
_dup();
@@ -459,12 +460,11 @@ amount_t& amount_t::operator-=(const amount_t& amt)
throw_(amount_error, _("Cannot subtract two uninitialized amounts"));
}
- if (has_commodity() && amt.has_commodity() &&
- commodity() != amt.commodity())
+ if (has_commodity() && amt.has_commodity() && commodity() != amt.commodity()) {
throw_(amount_error,
- _("Subtracting amounts with different commodities: %1 != %2")
- << (has_commodity() ? commodity().symbol() : _("NONE"))
- << (amt.has_commodity() ? amt.commodity().symbol() : _("NONE")));
+ _("Subtracting amounts with different commodities: '%1' != '%2'")
+ << commodity() << amt.commodity());
+ }
_dup();
@@ -605,16 +605,13 @@ void amount_t::in_place_negate()
}
}
-amount_t amount_t::inverted() const
+void amount_t::in_place_invert()
{
if (! quantity)
throw_(amount_error, _("Cannot invert an uninitialized amount"));
- amount_t t(*this);
- t._dup();
- mpq_inv(MP(t.quantity), MP(t.quantity));
-
- return t;
+ _dup();
+ mpq_inv(MP(quantity), MP(quantity));
}
void amount_t::in_place_round()
@@ -729,24 +726,24 @@ void amount_t::in_place_unreduce()
}
optional<amount_t>
-amount_t::value(const optional<datetime_t>& moment,
- const optional<commodity_t&>& in_terms_of) const
+amount_t::value(const datetime_t& moment,
+ const commodity_t * in_terms_of) const
{
if (quantity) {
#if defined(DEBUG_ON)
- DEBUG("commodity.prices.find",
+ DEBUG("commodity.price.find",
"amount_t::value of " << commodity().symbol());
- if (moment)
- DEBUG("commodity.prices.find",
- "amount_t::value: moment = " << *moment);
+ if (! moment.is_not_a_date_time())
+ DEBUG("commodity.price.find",
+ "amount_t::value: moment = " << moment);
if (in_terms_of)
- DEBUG("commodity.prices.find",
+ DEBUG("commodity.price.find",
"amount_t::value: in_terms_of = " << in_terms_of->symbol());
#endif
if (has_commodity() &&
(in_terms_of || ! commodity().has_flags(COMMODITY_PRIMARY))) {
optional<price_point_t> point;
- optional<commodity_t&> comm(in_terms_of);
+ const commodity_t * comm(in_terms_of);
if (has_annotation() && annotation().price) {
if (annotation().has_flags(ANNOTATION_PRICE_FIXATED)) {
@@ -756,14 +753,14 @@ amount_t::value(const optional<datetime_t>& moment,
"amount_t::value: fixated price = " << point->price);
}
else if (! comm) {
- comm = annotation().price->commodity();
+ comm = annotation().price->commodity_ptr();
}
}
- if (! point) {
- if (comm && commodity().referent() == comm->referent())
- return *this;
+ if (comm && commodity().referent() == comm->referent())
+ return with_commodity(comm->referent());
+ if (! point) {
point = commodity().find_price(comm, moment);
// Whether a price was found or not, check whether we should attempt
@@ -788,7 +785,7 @@ amount_t::value(const optional<datetime_t>& moment,
return none;
}
-amount_t amount_t::price() const
+optional<amount_t> amount_t::price() const
{
if (has_annotation() && annotation().price) {
amount_t tmp(*annotation().price);
@@ -796,7 +793,7 @@ amount_t amount_t::price() const
DEBUG("amount.price", "Returning price of " << *this << " = " << tmp);
return tmp;
}
- return *this;
+ return none;
}
@@ -868,10 +865,10 @@ bool amount_t::fits_in_long() const
return mpfr_fits_slong_p(tempf, GMP_RNDN);
}
-commodity_t& amount_t::commodity() const
+commodity_t * amount_t::commodity_ptr() const
{
- return (has_commodity() ?
- *commodity_ : *commodity_pool_t::current_pool->null_commodity);
+ return (commodity_ ?
+ commodity_ : commodity_pool_t::current_pool->null_commodity);
}
bool amount_t::has_commodity() const
@@ -1030,12 +1027,12 @@ bool amount_t::parse(std::istream& in, const parse_flags_t& flags)
}
// Allocate memory for the amount's quantity value. We have to
- // monitor the allocation in an auto_ptr because this function gets
+ // monitor the allocation in a unique_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> new_quantity;
+ unique_ptr<bigint_t> new_quantity;
if (quantity) {
if (quantity->refc > 1)
@@ -1061,10 +1058,6 @@ bool amount_t::parse(std::istream& in, const parse_flags_t& flags)
if (! commodity_)
commodity_ = commodity_pool_t::current_pool->create(symbol);
assert(commodity_);
-
- if (details)
- commodity_ =
- commodity_pool_t::current_pool->find_or_create(*commodity_, details);
}
// Quickly scan through and verify the correctness of the amount's use of
@@ -1200,6 +1193,14 @@ bool amount_t::parse(std::istream& in, const parse_flags_t& flags)
if (! flags.has_flags(PARSE_NO_REDUCE))
in_place_reduce(); // will not throw an exception
+ if (commodity_ && details) {
+ if (details.has_flags(ANNOTATION_PRICE_NOT_PER_UNIT)) {
+ assert(details.price);
+ *details.price /= this->abs();
+ }
+ set_commodity(*commodity_pool_t::current_pool->find_or_create(*commodity_, details));
+ }
+
VERIFY(valid());
return true;