summaryrefslogtreecommitdiff
path: root/balance.cc
diff options
context:
space:
mode:
Diffstat (limited to 'balance.cc')
-rw-r--r--balance.cc205
1 files changed, 160 insertions, 45 deletions
diff --git a/balance.cc b/balance.cc
index 5cfd88ca..a68f4ffe 100644
--- a/balance.cc
+++ b/balance.cc
@@ -13,6 +13,17 @@ amount_t balance_t::amount(const commodity_t& commodity) const
amounts_map::const_iterator i = amounts.begin();
return (*i).second;
}
+ else if (amounts.size() > 1) {
+ // Try stripping annotations before giving an error.
+ balance_t temp(strip_annotations());
+ if (temp.amounts.size() == 1)
+ return temp.amount(commodity);
+
+ std::ostringstream errmsg;
+ errmsg << "Requested amount of a balance with multiple commodities: "
+ << *this;
+ throw amount_error(errmsg.str());
+ }
}
else if (amounts.size() > 0) {
amounts_map::const_iterator i = amounts.find(&commodity);
@@ -63,15 +74,16 @@ std::time_t balance_t::date() const
return temp;
}
-balance_t balance_t::reduce(const bool keep_price, const bool keep_date,
- const bool keep_tag) const
+balance_t balance_t::strip_annotations(const bool keep_price,
+ const bool keep_date,
+ const bool keep_tag) const
{
balance_t temp;
for (amounts_map::const_iterator i = amounts.begin();
i != amounts.end();
i++)
- temp += (*i).second.reduce_commodity(keep_price, keep_date, keep_tag);
+ temp += (*i).second.strip_annotations(keep_price, keep_date, keep_tag);
return temp;
}
@@ -176,42 +188,148 @@ void balance_t::write(std::ostream& out,
balance_t& balance_t::operator*=(const balance_t& bal)
{
- if (! *this || ! bal) {
- return (*this = 0L);
+ if (realzero() || bal.realzero()) {
+ return *this = 0L;
}
- else if (amounts.size() == 1 && bal.amounts.size() == 1) {
+ else if (bal.amounts.size() == 1) {
return *this *= (*bal.amounts.begin()).second;
}
+ else if (amounts.size() == 1) {
+ return *this = bal * *this;
+ }
else {
+ // Since we would fail with an error at this point otherwise, try
+ // stripping annotations to see if we can come up with a
+ // reasonable result. The user will not notice any annotations
+ // missing (since they are viewing a stripped report anyway), only
+ // that some of their value expression may not see any pricing or
+ // date data because of this operation.
+
+ balance_t temp(bal.strip_annotations());
+ if (temp.amounts.size() == 1)
+ return *this *= temp;
+ temp = strip_annotations();
+ if (temp.amounts.size() == 1)
+ return *this = bal * temp;
+
std::ostringstream errmsg;
- errmsg << "It makes no sense to multiply two balances: "
- << *this << " * " << bal;
+ errmsg << "Cannot multiply two balances: " << *this << " * " << bal;
throw amount_error(errmsg.str());
}
}
-balance_t& balance_t::operator/=(const balance_t& bal)
+balance_t& balance_t::operator*=(const amount_t& amt)
{
- if (! *this) {
- return (*this = 0L);
+ if (realzero() || amt.realzero()) {
+ return *this = 0L;
+ }
+ else if (! amt.commodity()) {
+ // Multiplying by the null commodity causes all amounts to be
+ // increased by the same factor.
+ for (amounts_map::iterator i = amounts.begin();
+ i != amounts.end();
+ i++)
+ (*i).second *= amt;
+ }
+ else if (amounts.size() == 1 &&
+ (*amounts.begin()).first == &amt.commodity()) {
+ (*amounts.begin()).second *= amt;
}
- else if (! bal) {
+ else {
+ amounts_map::iterator i = amounts.find(&amt.commodity());
+ if (i != amounts.end()) {
+ (*i).second *= amt;
+ } else {
+ // Try stripping annotations before giving an error.
+ balance_t temp(strip_annotations());
+ if (temp.amounts.size() == 1 &&
+ (*temp.amounts.begin()).first == &amt.commodity()) {
+ return *this = temp * amt;
+ } else {
+ i = temp.amounts.find(&amt.commodity());
+ if (i != temp.amounts.end())
+ return *this = temp * amt;
+ }
+
+ std::ostringstream errmsg;
+ errmsg << "Attempt to multiply balance by a commodity"
+ << " not found in that balance: "
+ << *this << " * " << amt;
+ throw amount_error(errmsg.str());
+ }
+ }
+ return *this;
+}
+
+balance_t& balance_t::operator/=(const balance_t& bal)
+{
+ if (bal.realzero()) {
std::ostringstream errmsg;
errmsg << "Attempt to divide by zero: " << *this << " / " << bal;
throw amount_error(errmsg.str());
}
- else if (amounts.size() == 1 && bal.amounts.size() == 1) {
+ else if (realzero()) {
+ return *this = 0L;
+ }
+ else if (bal.amounts.size() == 1) {
return *this /= (*bal.amounts.begin()).second;
}
else if (*this == bal) {
- return (*this = 1L);
+ return *this = 1L;
}
else {
+ // Try stripping annotations before giving an error.
+ balance_t temp(bal.strip_annotations());
+ if (temp.amounts.size() == 1)
+ return *this /= temp;
+
+ std::ostringstream errmsg;
+ errmsg << "Cannot divide between two balances: " << *this << " / " << bal;
+ throw amount_error(errmsg.str());
+ }
+}
+
+balance_t& balance_t::operator/=(const amount_t& amt)
+{
+ if (amt.realzero()) {
std::ostringstream errmsg;
- errmsg << "It makes no sense to divide two balances: "
- << *this << " / " << bal;
+ errmsg << "Attempt to divide by zero: " << *this << " / " << amt;
throw amount_error(errmsg.str());
}
+ else if (realzero()) {
+ return *this = 0L;
+ }
+ else if (! amt.commodity()) {
+ // Dividing by the null commodity causes all amounts to be
+ // decreased by the same factor.
+ for (amounts_map::iterator i = amounts.begin();
+ i != amounts.end();
+ i++)
+ (*i).second /= amt;
+ }
+ else if (amounts.size() == 1 &&
+ (*amounts.begin()).first == &amt.commodity()) {
+ (*amounts.begin()).second /= amt;
+ }
+ else {
+ amounts_map::iterator i = amounts.find(&amt.commodity());
+ if (i != amounts.end()) {
+ (*i).second /= amt;
+ } else {
+ // Try stripping annotations before giving an error.
+ balance_t temp(strip_annotations());
+ if (temp.amounts.size() == 1 &&
+ (*temp.amounts.begin()).first == &amt.commodity())
+ return *this = temp / amt;
+
+ std::ostringstream errmsg;
+ errmsg << "Attempt to divide balance by a commodity"
+ << " not found in that balance: "
+ << *this << " * " << amt;
+ throw amount_error(errmsg.str());
+ }
+ }
+ return *this;
}
balance_t::operator amount_t() const
@@ -223,6 +341,11 @@ balance_t::operator amount_t() const
return amount_t();
}
else {
+ // Try stripping annotations before giving an error.
+ balance_t temp(strip_annotations());
+ if (temp.amounts.size() == 1)
+ return (*temp.amounts.begin()).second;
+
std::ostringstream errmsg;
errmsg << "Cannot convert a balance with "
<< "multiple commodities to an amount: " << *this;
@@ -230,27 +353,6 @@ balance_t::operator amount_t() const
}
}
-balance_pair_t& balance_pair_t::operator/=(const balance_pair_t& bal_pair)
-{
- if (bal_pair.cost && ! cost)
- cost = new balance_t(quantity);
- quantity /= bal_pair.quantity;
- if (cost)
- *cost /= bal_pair.cost ? *bal_pair.cost : bal_pair.quantity;
- return *this;
-}
-
-balance_pair_t& balance_pair_t::add(const amount_t& amount,
- const amount_t * a_cost)
-{
- if (a_cost && ! cost)
- cost = new balance_t(quantity);
- quantity += amount;
- if (cost)
- *cost += a_cost ? *a_cost : amount;
- return *this;
-}
-
} // namespace ledger
#ifdef USE_BOOST_PYTHON
@@ -353,13 +455,19 @@ void export_balance()
.def("__len__", balance_len)
.def("__getitem__", balance_getitem)
- .def("negate", &balance_t::negate)
+ .def("valid", &balance_t::valid)
+
+ .def("realzero", &balance_t::realzero)
.def("amount", &balance_t::amount)
.def("value", &balance_t::value)
.def("price", &balance_t::price)
- .def("reduce", &balance_t::reduce)
+ .def("date", &balance_t::date)
+ .def("strip_annotations", &balance_t::strip_annotations)
.def("write", &balance_t::write)
- .def("valid", &balance_t::valid)
+ .def("abs", &balance_t::abs)
+ .def("round", &balance_t::round)
+ .def("negate", &balance_t::negate)
+ .def("negated", &balance_t::negated)
;
class_< balance_pair_t > ("BalancePair")
@@ -436,16 +544,23 @@ void export_balance()
.def("__len__", balance_pair_len)
.def("__getitem__", balance_pair_getitem)
- .add_property("cost",
- make_getter(&balance_pair_t::cost,
- return_value_policy<reference_existing_object>()))
+ .def("valid", &balance_pair_t::valid)
- .def("negate", &balance_pair_t::negate)
+ .def("realzero", &balance_pair_t::realzero)
.def("amount", &balance_pair_t::amount)
.def("value", &balance_pair_t::value)
+ .def("price", &balance_pair_t::price)
+ .def("date", &balance_pair_t::date)
+ .def("strip_annotations", &balance_pair_t::strip_annotations)
.def("write", &balance_pair_t::write)
+ .def("abs", &balance_pair_t::abs)
+ .def("round", &balance_pair_t::round)
+ .def("negate", &balance_pair_t::negate)
+ .def("negated", &balance_pair_t::negated)
- .def("valid", &balance_pair_t::valid)
+ .add_property("cost",
+ make_getter(&balance_pair_t::cost,
+ return_value_policy<reference_existing_object>()))
;
}