diff options
Diffstat (limited to 'src/balance.cc')
-rw-r--r-- | src/balance.cc | 216 |
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 |