summaryrefslogtreecommitdiff
path: root/src/balance.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/balance.cc')
-rw-r--r--src/balance.cc216
1 files changed, 124 insertions, 92 deletions
diff --git a/src/balance.cc b/src/balance.cc
index 80ddd2e4..80637221 100644
--- a/src/balance.cc
+++ b/src/balance.cc
@@ -33,98 +33,169 @@
namespace ledger {
+balance_t& balance_t::operator+=(const balance_t& bal)
+{
+ for (amounts_map::const_iterator i = bal.amounts.begin();
+ i != bal.amounts.end();
+ i++)
+ *this += i->second;
+ return *this;
+}
+
+balance_t& balance_t::operator+=(const amount_t& amt)
+{
+ if (amt.is_null())
+ throw_(balance_error,
+ "Cannot add an uninitialized amount to a balance");
+
+ if (amt.is_realzero())
+ return *this;
+
+ amounts_map::iterator i = amounts.find(&amt.commodity());
+ if (i != amounts.end())
+ i->second += amt;
+ else
+ amounts.insert(amounts_map::value_type(&amt.commodity(), amt));
+
+ return *this;
+}
+
+balance_t& balance_t::operator-=(const balance_t& bal)
+{
+ for (amounts_map::const_iterator i = bal.amounts.begin();
+ i != bal.amounts.end();
+ i++)
+ *this -= i->second;
+ return *this;
+}
+
+balance_t& balance_t::operator-=(const amount_t& amt)
+{
+ if (amt.is_null())
+ throw_(balance_error,
+ "Cannot subtract an uninitialized amount from a balance");
+
+ if (amt.is_realzero())
+ return *this;
+
+ amounts_map::iterator i = amounts.find(&amt.commodity());
+ if (i != amounts.end()) {
+ i->second -= amt;
+ if (i->second.is_realzero())
+ amounts.erase(i);
+ } else {
+ amounts.insert(amounts_map::value_type(&amt.commodity(), amt.negate()));
+ }
+ return *this;
+}
+
balance_t& balance_t::operator*=(const amount_t& amt)
{
+ if (amt.is_null())
+ throw_(balance_error,
+ "Cannot multiply a balance by an uninitialized amount");
+
if (is_realzero()) {
- return *this;
+ ;
}
else if (amt.is_realzero()) {
- return *this = amt;
+ *this = amt;
}
else if (! amt.commodity()) {
- // Multiplying by the null commodity causes all amounts to be
- // increased by the same factor.
+ // Multiplying by an amount with no commodity causes all the
+ // component amounts to be increased by the same factor.
for (amounts_map::iterator i = amounts.begin();
i != amounts.end();
i++)
- (*i).second *= amt;
+ i->second *= amt;
}
else if (amounts.size() == 1) {
- *this = (*amounts.begin()).second * amt;
+ // Multiplying by a commoditized amount is only valid if the sole
+ // commodity in the balance is of the same kind as the amount's
+ // commodity.
+ if (*amounts.begin()->first == amt.commodity())
+ amounts.begin()->second *= amt;
+ else
+ throw_(balance_error,
+ "Cannot multiply a balance with annotated commodities by a commoditized amount");
}
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) {
- return *this = (*temp.amounts.begin()).second * amt;
- } else {
- i = temp.amounts.find(&amt.commodity());
- if (i != temp.amounts.end())
- return *this = temp * amt;
- }
-
- throw_(amount_error, "Attempt to multiply balance by a commodity" <<
- " not found in that balance: " << temp << " * " << amt);
- }
+ assert(amounts.size() > 1);
+ throw_(balance_error,
+ "Cannot multiply a multi-commodity balance by a commoditized amount");
}
return *this;
}
balance_t& balance_t::operator/=(const amount_t& amt)
{
- if (amt.is_realzero()) {
- throw_(amount_error, "Divide by zero: " << *this << " / " << amt);
+ if (amt.is_null())
+ throw_(balance_error,
+ "Cannot divide a balance by an uninitialized amount");
+
+ if (is_realzero()) {
+ ;
}
- else if (is_realzero()) {
- return *this;
+ else if (amt.is_realzero()) {
+ throw_(balance_error, "Divide by zero");
}
else if (! amt.commodity()) {
- // Dividing by the null commodity causes all amounts to be
- // decreased by the same factor.
+ // Dividing by an amount with no commodity causes all the
+ // component amounts to be divided by the same factor.
for (amounts_map::iterator i = amounts.begin();
i != amounts.end();
i++)
- (*i).second /= amt;
+ i->second /= amt;
}
- else if (amounts.size() == 1 &&
- (*amounts.begin()).first == &amt.commodity()) {
- (*amounts.begin()).second /= amt;
+ else if (amounts.size() == 1) {
+ // Dividing by a commoditized amount is only valid if the sole
+ // commodity in the balance is of the same kind as the amount's
+ // commodity.
+ if (*amounts.begin()->first == amt.commodity())
+ amounts.begin()->second /= amt;
+ else
+ throw_(balance_error,
+ "Cannot divide a balance with annotated commodities by a commoditized amount");
}
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;
-
- throw_(amount_error, "Attempt to divide balance by a commodity" <<
- " not found in that balance: " << temp << " * " << amt);
- }
+ assert(amounts.size() > 1);
+ throw_(balance_error,
+ "Cannot divide a multi-commodity balance by a commoditized amount");
}
return *this;
}
+optional<balance_t>
+balance_t::value(const optional<moment_t>& moment) const
+{
+ optional<balance_t> temp;
+
+ for (amounts_map::const_iterator i = amounts.begin();
+ i != amounts.end();
+ i++)
+ if (optional<amount_t> val = i->second.value(moment)) {
+ if (! temp)
+ temp = balance_t();
+ *temp += *val;
+ }
+
+ return temp;
+}
+
optional<amount_t>
-balance_t::amount(const optional<const commodity_t&>& commodity) const
+balance_t::commodity_amount(const optional<const commodity_t&>& commodity) const
{
+ // jww (2007-05-20): Needs work
if (! commodity) {
if (amounts.size() == 1) {
amounts_map::const_iterator i = amounts.begin();
- return (*i).second;
+ 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);
+ return temp.commodity_amount(commodity);
throw_(amount_error,
"Requested amount of a balance with multiple commodities: " << temp);
@@ -133,28 +204,11 @@ balance_t::amount(const optional<const commodity_t&>& commodity) const
else if (amounts.size() > 0) {
amounts_map::const_iterator i = amounts.find(&*commodity);
if (i != amounts.end())
- return (*i).second;
+ return i->second;
}
return none;
}
-optional<balance_t>
-balance_t::value(const optional<moment_t>& moment) const
-{
- optional<balance_t> temp;
-
- for (amounts_map::const_iterator i = amounts.begin();
- i != amounts.end();
- i++)
- if (optional<amount_t> val = (*i).second.value(moment)) {
- if (! temp)
- temp = balance_t();
- *temp += *val;
- }
-
- return temp;
-}
-
balance_t balance_t::strip_annotations(const bool keep_price,
const bool keep_date,
const bool keep_tag) const
@@ -164,7 +218,7 @@ balance_t balance_t::strip_annotations(const bool keep_price,
for (amounts_map::const_iterator i = amounts.begin();
i != amounts.end();
i++)
- temp += (*i).second.strip_annotations(keep_price, keep_date, keep_tag);
+ temp += i->second.strip_annotations(keep_price, keep_date, keep_tag);
return temp;
}
@@ -185,8 +239,8 @@ void balance_t::print(std::ostream& out,
for (amounts_map::const_iterator i = amounts.begin();
i != amounts.end();
i++)
- if ((*i).second)
- sorted.push_back(&(*i).second);
+ if (i->second)
+ sorted.push_back(&i->second);
std::stable_sort(sorted.begin(), sorted.end(),
compare_amount_commodities());
@@ -215,26 +269,4 @@ void balance_t::print(std::ostream& out,
}
}
-#if 0
-balance_t::operator amount_t() const
-{
- if (amounts.size() == 1) {
- return (*amounts.begin()).second;
- }
- else if (amounts.size() == 0) {
- 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;
-
- throw_(amount_error,
- "Cannot convert a balance with " <<
- "multiple commodities to an amount: " << temp);
- }
-}
-#endif
-
} // namespace ledger