diff options
author | John Wiegley <johnw@newartisans.com> | 2004-11-08 06:43:11 +0000 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2008-04-13 02:40:47 -0400 |
commit | c9fb11bd60a2170fb896d77ff8d7706f563ad597 (patch) | |
tree | 42bdf09e7d8727ba31d1d8dae9b4eb4b2a605441 /balance.h | |
parent | fa2ceaed13c031add578ee8eb33da0c9980b9fb1 (diff) | |
download | fork-ledger-c9fb11bd60a2170fb896d77ff8d7706f563ad597.tar.gz fork-ledger-c9fb11bd60a2170fb896d77ff8d7706f563ad597.tar.bz2 fork-ledger-c9fb11bd60a2170fb896d77ff8d7706f563ad597.zip |
updated to version 2.0
Diffstat (limited to 'balance.h')
-rw-r--r-- | balance.h | 893 |
1 files changed, 893 insertions, 0 deletions
diff --git a/balance.h b/balance.h new file mode 100644 index 00000000..8a6e4a35 --- /dev/null +++ b/balance.h @@ -0,0 +1,893 @@ +#ifndef _BALANCE_H +#define _BALANCE_H + +#include "amount.h" + +#include <map> +#include <ctime> +#include <iostream> + +namespace ledger { + +typedef std::map<const commodity_t *, amount_t> amounts_map; +typedef std::pair<const commodity_t *, amount_t> amounts_pair; + +class balance_t +{ + public: + amounts_map amounts; + + bool valid() const { + for (amounts_map::const_iterator i = amounts.begin(); + i != amounts.end(); + i++) + if (! (*i).second.valid()) + return false; + return true; + } + + // constructors + balance_t() {} + balance_t(const balance_t& bal) { + for (amounts_map::const_iterator i = bal.amounts.begin(); + i != bal.amounts.end(); + i++) + *this += (*i).second; + } + balance_t(const amount_t& amt) { + if (amt) + amounts.insert(amounts_pair(&amt.commodity(), amt)); + } + template <typename T> + balance_t(T value) { + amount_t amt(value); + if (amt) + amounts.insert(amounts_pair(&amt.commodity(), amt)); + } + + // assignment operator + balance_t& operator=(const balance_t& bal) { + if (this != &bal) { + amounts.clear(); + for (amounts_map::const_iterator i = bal.amounts.begin(); + i != bal.amounts.end(); + i++) + *this += (*i).second; + } + return *this; + } + balance_t& operator=(const amount_t& amt) { + amounts.clear(); + *this += amt; + return *this; + } + template <typename T> + balance_t& operator=(T value) { + amounts.clear(); + *this += value; + return *this; + } + + // in-place arithmetic + 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& operator+=(const amount_t& amt) { + amounts_map::iterator i = amounts.find(&amt.commodity()); + if (i != amounts.end()) + (*i).second += amt; + else if (amt) + amounts.insert(amounts_pair(&amt.commodity(), amt)); + return *this; + } + template <typename T> + balance_t& operator+=(T val) { + return *this += amount_t(val); + } + 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& operator-=(const amount_t& amt) { + amounts_map::iterator i = amounts.find(&amt.commodity()); + if (i != amounts.end()) + (*i).second -= amt; + else if (amt) + amounts.insert(amounts_pair(&amt.commodity(), amt)); + return *this; + } + template <typename T> + balance_t& operator-=(T val) { + return *this -= amount_t(val); + } + + // simple arithmetic + balance_t operator+(const balance_t& bal) const { + balance_t temp = *this; + temp += bal; + return temp; + } + balance_t operator+(const amount_t& amt) const { + balance_t temp = *this; + temp += amt; + return temp; + } + template <typename T> + balance_t operator+(T val) const { + balance_t temp = *this; + temp += val; + return temp; + } + balance_t operator-(const balance_t& bal) const { + balance_t temp = *this; + temp -= bal; + return temp; + } + balance_t operator-(const amount_t& amt) const { + balance_t temp = *this; + temp -= amt; + return temp; + } + template <typename T> + balance_t operator-(T val) const { + balance_t temp = *this; + temp -= val; + return temp; + } + + // multiplication and divide + balance_t& operator*=(const balance_t& bal) { + if (amounts.size() == 1 && bal.amounts.size() == 1) + return *this *= (*bal.amounts.begin()).second; + throw amount_error("It makes no sense to multiply two balances"); + } + balance_t& operator*=(const amount_t& amt) { + // Multiplying by the null commodity causes all amounts to be + // increased by the same factor. + if (amt.commodity().symbol.empty()) { + for (amounts_map::iterator i = amounts.begin(); + i != amounts.end(); + i++) + (*i).second *= amt; + } + else if (amounts.size() == 1) { + (*amounts.begin()).second *= amt; + } + else { + amounts_map::iterator i = amounts.find(&amt.commodity()); + if (i != amounts.end()) + (*i).second *= amt; + } + return *this; + } + template <typename T> + balance_t& operator*=(T val) { + return *this *= amount_t(val); + } + + balance_t& operator/=(const balance_t& bal) { + if (amounts.size() == 1 && bal.amounts.size() == 1) + return *this /= (*bal.amounts.begin()).second; + throw amount_error("It makes no sense to divide two balances"); + } + balance_t& operator/=(const amount_t& amt) { + // Dividing by the null commodity causes all amounts to be + // increased by the same factor. + if (amt.commodity().symbol.empty()) { + for (amounts_map::iterator i = amounts.begin(); + i != amounts.end(); + i++) + (*i).second /= amt; + } + else if (amounts.size() == 1) { + (*amounts.begin()).second /= amt; + } + else { + amounts_map::iterator i = amounts.find(&amt.commodity()); + if (i != amounts.end()) + (*i).second /= amt; + } + return *this; + } + template <typename T> + balance_t& operator/=(T val) { + return *this /= amount_t(val); + } + + // multiplication and divide + balance_t operator*(const balance_t& bal) const { + balance_t temp = *this; + temp *= bal; + return temp; + } + balance_t operator*(const amount_t& amt) const { + balance_t temp = *this; + temp *= amt; + return temp; + } + template <typename T> + balance_t operator*(T val) const { + balance_t temp = *this; + temp *= val; + return temp; + } + balance_t operator/(const balance_t& bal) const { + balance_t temp = *this; + temp /= bal; + return temp; + } + balance_t operator/(const amount_t& amt) const { + balance_t temp = *this; + temp /= amt; + return temp; + } + template <typename T> + balance_t operator/(T val) const { + balance_t temp = *this; + temp /= val; + return temp; + } + + // comparison + bool operator<(const balance_t& bal) const { + for (amounts_map::const_iterator i = bal.amounts.begin(); + i != bal.amounts.end(); + i++) + if (! (amount(*(*i).first) < (*i).second)) + return false; + + for (amounts_map::const_iterator i = amounts.begin(); + i != amounts.end(); + i++) + if (! ((*i).second < bal.amount(*(*i).first))) + return false; + + if (bal.amounts.size() == 0 && amounts.size() == 0) + return false; + + return true; + } + bool operator<(const amount_t& amt) const { + return amount(amt.commodity()) < amt; + } + template <typename T> + bool operator<(T val) const { + for (amounts_map::const_iterator i = amounts.begin(); + i != amounts.end(); + i++) + if ((*i).second < val) + return true; + return false; + } + + bool operator<=(const balance_t& bal) const { + for (amounts_map::const_iterator i = bal.amounts.begin(); + i != bal.amounts.end(); + i++) + if (! (amount(*(*i).first) <= (*i).second)) + return false; + + for (amounts_map::const_iterator i = amounts.begin(); + i != amounts.end(); + i++) + if (! ((*i).second <= bal.amount(*(*i).first))) + return false; + + return true; + } + bool operator<=(const amount_t& amt) const { + return amount(amt.commodity()) <= amt; + } + template <typename T> + bool operator<=(T val) const { + for (amounts_map::const_iterator i = amounts.begin(); + i != amounts.end(); + i++) + if ((*i).second <= val) + return true; + return false; + } + + bool operator>(const balance_t& bal) const { + for (amounts_map::const_iterator i = bal.amounts.begin(); + i != bal.amounts.end(); + i++) + if (! (amount(*(*i).first) > (*i).second)) + return false; + + for (amounts_map::const_iterator i = amounts.begin(); + i != amounts.end(); + i++) + if (! ((*i).second > bal.amount(*(*i).first))) + return false; + + if (bal.amounts.size() == 0 && amounts.size() == 0) + return false; + + return true; + } + bool operator>(const amount_t& amt) const { + return amount(amt.commodity()) > amt; + } + template <typename T> + bool operator>(T val) const { + for (amounts_map::const_iterator i = amounts.begin(); + i != amounts.end(); + i++) + if ((*i).second > val) + return true; + return false; + } + + bool operator>=(const balance_t& bal) const { + for (amounts_map::const_iterator i = bal.amounts.begin(); + i != bal.amounts.end(); + i++) + if (! (amount(*(*i).first) >= (*i).second)) + return false; + + for (amounts_map::const_iterator i = amounts.begin(); + i != amounts.end(); + i++) + if (! ((*i).second >= bal.amount(*(*i).first))) + return false; + + return true; + } + bool operator>=(const amount_t& amt) const { + return amount(amt.commodity()) >= amt; + } + template <typename T> + bool operator>=(T val) const { + for (amounts_map::const_iterator i = amounts.begin(); + i != amounts.end(); + i++) + if ((*i).second >= val) + return true; + return false; + } + + bool operator==(const balance_t& bal) const { + amounts_map::const_iterator i, j; + for (i = amounts.begin(), j = bal.amounts.begin(); + i != amounts.end() && j != bal.amounts.end(); + i++, j++) { + if (! ((*i).first == (*j).first && + (*i).second == (*j).second)) + return false; + } + return i == amounts.end() && j == bal.amounts.end(); + } + bool operator==(const amount_t& amt) const { + return amounts.size() == 1 && (*amounts.begin()).second == amt; + } + template <typename T> + bool operator==(T val) const { + for (amounts_map::const_iterator i = amounts.begin(); + i != amounts.end(); + i++) + if ((*i).second == val) + return true; + return false; + } + + bool operator!=(const balance_t& bal) const { + return ! (*this == bal); + } + bool operator!=(const amount_t& amt) const { + return ! (*this == amt); + } + template <typename T> + bool operator!=(T val) const { + return ! (*this == val); + } + + // unary negation + void negate() { + for (amounts_map::iterator i = amounts.begin(); + i != amounts.end(); + i++) + (*i).second.negate(); + } + balance_t negated() const { + balance_t temp = *this; + temp.negate(); + return temp; + } + balance_t operator-() const { + return negated(); + } + + // conversion operators + operator amount_t() const { + if (amounts.size() == 1) + return (*amounts.begin()).second; + else if (amounts.size() == 0) + return amount_t(); + else + throw amount_error("Cannot convert a balance with " + "multiple commodities to an amount"); + } + operator bool() const { + for (amounts_map::const_iterator i = amounts.begin(); + i != amounts.end(); + i++) + if ((*i).second) + return true; + return false; + } + + amount_t amount(const commodity_t& commodity) const; + balance_t value(const std::time_t moment) const; + + void write(std::ostream& out, + const int first_width, + const int latter_width = -1) const; + + void abs() { + for (amounts_map::iterator i = amounts.begin(); + i != amounts.end(); + i++) + (*i).second.abs(); + } + + void round() { + for (amounts_map::iterator i = amounts.begin(); + i != amounts.end(); + i++) + if ((*i).second.commodity()) + (*i).second = (*i).second.round((*i).second.commodity().precision); + } +}; + +inline balance_t abs(const balance_t& bal) { + balance_t temp = bal; + temp.abs(); + return temp; +} + +inline std::ostream& operator<<(std::ostream& out, const balance_t& bal) { + bal.write(out, 12); + return out; +} + + +class balance_pair_t +{ + public: + balance_t quantity; + balance_t * cost; + + // constructors + balance_pair_t() : cost(NULL) {} + balance_pair_t(const balance_pair_t& bal_pair) + : quantity(bal_pair.quantity), cost(NULL) { + if (bal_pair.cost) + cost = new balance_t(*bal_pair.cost); + } + balance_pair_t(const balance_t& _quantity) + : quantity(_quantity), cost(NULL) {} + balance_pair_t(const amount_t& _quantity) + : quantity(_quantity), cost(NULL) {} + template <typename T> + balance_pair_t(T value) : quantity(value), cost(NULL) {} + + // destructor + ~balance_pair_t() { + if (cost) + delete cost; + } + + // assignment operator + balance_pair_t& operator=(const balance_pair_t& bal_pair) { + if (this != &bal_pair) { + if (cost) { + delete cost; + cost = NULL; + } + + quantity = bal_pair.quantity; + if (bal_pair.cost) + cost = new balance_t(*bal_pair.cost); + } + return *this; + } + balance_pair_t& operator=(const balance_t& bal) { + if (cost) { + delete cost; + cost = NULL; + } + quantity = bal; + return *this; + } + balance_pair_t& operator=(const amount_t& amt) { + if (cost) { + delete cost; + cost = NULL; + } + quantity = amt; + return *this; + } + template <typename T> + balance_pair_t& operator=(T value) { + if (cost) { + delete cost; + cost = NULL; + } + quantity = value; + return *this; + } + + // in-place arithmetic + 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& operator+=(const balance_t& bal) { + quantity += bal; + if (cost) + *cost += bal; + return *this; + } + balance_pair_t& operator+=(const amount_t& amt) { + quantity += amt; + if (cost) + *cost += amt; + return *this; + } + template <typename T> + balance_pair_t& operator+=(T val) { + return *this += amount_t(val); + } + + 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& operator-=(const balance_t& bal) { + quantity -= bal; + if (cost) + *cost -= bal; + return *this; + } + balance_pair_t& operator-=(const amount_t& amt) { + quantity -= amt; + if (cost) + *cost -= amt; + return *this; + } + template <typename T> + balance_pair_t& operator-=(T val) { + return *this -= amount_t(val); + } + + // simple arithmetic + balance_pair_t operator+(const balance_pair_t& bal_pair) const { + balance_pair_t temp = *this; + temp += bal_pair; + return temp; + } + balance_pair_t operator+(const balance_t& bal) const { + balance_pair_t temp = *this; + temp += bal; + return temp; + } + balance_pair_t operator+(const amount_t& amt) const { + balance_pair_t temp = *this; + temp += amt; + return temp; + } + template <typename T> + balance_pair_t operator+(T val) const { + balance_pair_t temp = *this; + temp += val; + return temp; + } + + balance_pair_t operator-(const balance_pair_t& bal_pair) const { + balance_pair_t temp = *this; + temp -= bal_pair; + return temp; + } + balance_pair_t operator-(const balance_t& bal) const { + balance_pair_t temp = *this; + temp -= bal; + return temp; + } + balance_pair_t operator-(const amount_t& amt) const { + balance_pair_t temp = *this; + temp -= amt; + return temp; + } + template <typename T> + balance_pair_t operator-(T val) const { + balance_pair_t temp = *this; + temp -= val; + return temp; + } + + // multiplication and division + 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& operator*=(const balance_t& bal) { + quantity *= bal; + if (cost) + *cost *= bal; + return *this; + } + balance_pair_t& operator*=(const amount_t& amt) { + quantity *= amt; + if (cost) + *cost *= amt; + return *this; + } + template <typename T> + balance_pair_t& operator*=(T val) { + return *this *= amount_t(val); + } + + 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& operator/=(const balance_t& bal) { + quantity /= bal; + if (cost) + *cost /= bal; + return *this; + } + balance_pair_t& operator/=(const amount_t& amt) { + quantity /= amt; + if (cost) + *cost /= amt; + return *this; + } + template <typename T> + balance_pair_t& operator/=(T val) { + return *this /= amount_t(val); + } + + balance_pair_t operator*(const balance_pair_t& bal_pair) const { + balance_pair_t temp = *this; + temp *= bal_pair; + return temp; + } + balance_pair_t operator*(const balance_t& bal) const { + balance_pair_t temp = *this; + temp *= bal; + return temp; + } + balance_pair_t operator*(const amount_t& amt) const { + balance_pair_t temp = *this; + temp *= amt; + return temp; + } + template <typename T> + balance_pair_t operator*(T val) const { + balance_pair_t temp = *this; + temp *= val; + return temp; + } + + balance_pair_t operator/(const balance_pair_t& bal_pair) const { + balance_pair_t temp = *this; + temp /= bal_pair; + return temp; + } + balance_pair_t operator/(const balance_t& bal) const { + balance_pair_t temp = *this; + temp /= bal; + return temp; + } + balance_pair_t operator/(const amount_t& amt) const { + balance_pair_t temp = *this; + temp /= amt; + return temp; + } + template <typename T> + balance_pair_t operator/(T val) const { + balance_pair_t temp = *this; + temp /= val; + return temp; + } + + // comparison + bool operator<(const balance_pair_t& bal_pair) const { + return quantity < bal_pair.quantity; + } + bool operator<(const balance_t& bal) const { + return quantity < bal; + } + bool operator<(const amount_t& amt) const { + return quantity < amt; + } + template <typename T> + bool operator<(T val) const { + return quantity < val; + } + + bool operator<=(const balance_pair_t& bal_pair) const { + return quantity <= bal_pair.quantity; + } + bool operator<=(const balance_t& bal) const { + return quantity <= bal; + } + bool operator<=(const amount_t& amt) const { + return quantity <= amt; + } + template <typename T> + bool operator<=(T val) const { + return quantity <= val; + } + + bool operator>(const balance_pair_t& bal_pair) const { + return quantity > bal_pair.quantity; + } + bool operator>(const balance_t& bal) const { + return quantity > bal; + } + bool operator>(const amount_t& amt) const { + return quantity > amt; + } + template <typename T> + bool operator>(T val) const { + return quantity > val; + } + + bool operator>=(const balance_pair_t& bal_pair) const { + return quantity >= bal_pair.quantity; + } + bool operator>=(const balance_t& bal) const { + return quantity >= bal; + } + bool operator>=(const amount_t& amt) const { + return quantity >= amt; + } + template <typename T> + bool operator>=(T val) const { + return quantity >= val; + } + + bool operator==(const balance_pair_t& bal_pair) const { + return quantity == bal_pair.quantity; + } + bool operator==(const balance_t& bal) const { + return quantity == bal; + } + bool operator==(const amount_t& amt) const { + return quantity == amt; + } + template <typename T> + bool operator==(T val) const { + return quantity == val; + } + + bool operator!=(const balance_pair_t& bal_pair) const { + return ! (*this == bal_pair); + } + bool operator!=(const balance_t& bal) const { + return ! (*this == bal); + } + bool operator!=(const amount_t& amt) const { + return ! (*this == amt); + } + template <typename T> + bool operator!=(T val) const { + return ! (*this == val); + } + + // unary negation + void negate() { + quantity.negate(); + if (cost) + cost->negate(); + } + balance_pair_t negated() const { + balance_pair_t temp = *this; + temp.negate(); + return temp; + } + balance_pair_t operator-() const { + return negated(); + } + + // test for non-zero (use ! for zero) + operator bool() const { + return quantity; + } + operator balance_t() const { + return quantity; + } + operator amount_t() const { + return quantity; + } + + void abs() { + quantity.abs(); + if (cost) + cost->abs(); + } + + amount_t amount(const commodity_t& commodity) const { + return quantity.amount(commodity); + } + balance_t value(const std::time_t moment) const { + return quantity.value(moment); + } + void write(std::ostream& out, + const int first_width, + const int latter_width = -1) const { + quantity.write(out, first_width, latter_width); + } + + balance_pair_t& add(const amount_t& amount, + const amount_t * a_cost = NULL) { + if (a_cost && ! cost) + cost = new balance_t(quantity); + + quantity += amount; + if (cost) + *cost += a_cost ? *a_cost : amount; + + return *this; + } + + bool valid() { + return quantity.valid() && (! cost || cost->valid()); + } + + void round() { + quantity.round(); + } +}; + +inline balance_pair_t abs(const balance_pair_t& bal_pair) { + balance_pair_t temp; + temp.abs(); + return temp; +} + +inline std::ostream& operator<<(std::ostream& out, + const balance_pair_t& bal_pair) { + bal_pair.quantity.write(out, 12); + return out; +} + +} // namespace ledger + +#endif // _BALANCE_H |