diff options
-rw-r--r-- | src/amount.cc | 91 | ||||
-rw-r--r-- | src/amount.h | 62 | ||||
-rw-r--r-- | src/balance.cc | 262 | ||||
-rw-r--r-- | src/balance.h | 193 | ||||
-rw-r--r-- | src/binary.cc | 2 | ||||
-rw-r--r-- | src/journal.cc | 15 | ||||
-rw-r--r-- | src/py_amount.cc | 2 | ||||
-rw-r--r-- | src/pyinterp.cc | 10 | ||||
-rw-r--r-- | src/report.cc | 10 | ||||
-rw-r--r-- | src/report.h | 8 | ||||
-rw-r--r-- | src/session.h | 2 | ||||
-rw-r--r-- | src/textual.cc | 2 | ||||
-rw-r--r-- | src/value.cc | 92 | ||||
-rw-r--r-- | src/value.h | 55 | ||||
-rw-r--r-- | src/xpath.cc | 34 | ||||
-rw-r--r-- | src/xpath.h | 2 |
16 files changed, 319 insertions, 523 deletions
diff --git a/src/amount.cc b/src/amount.cc index 111b91a7..cc76ed3e 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -410,58 +410,6 @@ amount_t& amount_t::operator=(const amount_t& amt) return *this; } -#if 0 -amount_t& amount_t::operator=(const long val) -{ - if (val == 0) { - if (quantity) - _clear(); - } else { - commodity_ = NULL; - _init(); - mpz_set_si(MPZ(quantity), val); - } - return *this; -} - -amount_t& amount_t::operator=(const unsigned long val) -{ - if (val == 0) { - if (quantity) - _clear(); - } else { - commodity_ = NULL; - _init(); - mpz_set_ui(MPZ(quantity), val); - } - return *this; -} - -amount_t& amount_t::operator=(const double val) -{ - commodity_ = NULL; - _init(); - quantity->prec = convert_double(MPZ(quantity), val); - return *this; -} - -amount_t& amount_t::operator=(const string& val) -{ - std::istringstream str(val); - parse(str); - return *this; -} - -amount_t& amount_t::operator=(const char * val) -{ - string valstr(val); - std::istringstream str(valstr); - parse(str); - return *this; -} -#endif - - amount_t& amount_t::operator+=(const amount_t& amt) { if (commodity() != amt.commodity()) @@ -702,45 +650,6 @@ bool amount_t::zero() const return realzero(); } -#if 0 -amount_t::operator long() const -{ - if (! quantity) - return 0; - - mpz_set(temp, MPZ(quantity)); - mpz_ui_pow_ui(divisor, 10, quantity->prec); - mpz_tdiv_q(temp, temp, divisor); - return mpz_get_si(temp); -} - -amount_t::operator double() const -{ - if (! quantity) - return 0.0; - - mpz_t remainder; - mpz_init(remainder); - - mpz_set(temp, MPZ(quantity)); - mpz_ui_pow_ui(divisor, 10, quantity->prec); - mpz_tdiv_qr(temp, remainder, temp, divisor); - - char * quotient_s = mpz_get_str(NULL, 10, temp); - char * remainder_s = mpz_get_str(NULL, 10, remainder); - - std::ostringstream num; - num << quotient_s << '.' << remainder_s; - - std::free(quotient_s); - std::free(remainder_s); - - mpz_clear(remainder); - - return std::atof(num.str().c_str()); -} -#endif - amount_t amount_t::value(const moment_t& moment) const { if (quantity) { diff --git a/src/amount.h b/src/amount.h index b4b5df54..f3109f33 100644 --- a/src/amount.h +++ b/src/amount.h @@ -69,9 +69,13 @@ DECLARE_EXCEPTION(amount_error); * uncommoditized numbers, no display truncation is ever done. * Internally, precision is always kept to an excessive degree. */ -class amount_t : public ordered_field_operators<amount_t> + class amount_t + : public ordered_field_operators<amount_t, + ordered_field_operators<amount_t, long, + ordered_field_operators<amount_t, unsigned long, + ordered_field_operators<amount_t, double > > > > { - public: +public: class bigint_t; static void initialize(); @@ -83,7 +87,7 @@ class amount_t : public ordered_field_operators<amount_t> static bool keep_base; static bool full_strings; - protected: +protected: void _init(); void _copy(const amount_t& amt); void _release(); @@ -94,7 +98,7 @@ class amount_t : public ordered_field_operators<amount_t> bigint_t * quantity; commodity_t * commodity_; - public: +public: // constructors amount_t() : quantity(NULL), commodity_(NULL) { TRACE_CTOR(amount_t, ""); @@ -125,15 +129,10 @@ class amount_t : public ordered_field_operators<amount_t> _release(); } + static amount_t exact(const string& value); + // assignment operator amount_t& operator=(const amount_t& amt); -#if 0 - amount_t& operator=(const double val); - amount_t& operator=(const unsigned long val); - amount_t& operator=(const long val); - amount_t& operator=(const string& val); - amount_t& operator=(const char * val); -#endif // comparisons between amounts int compare(const amount_t& amt) const; @@ -149,28 +148,33 @@ class amount_t : public ordered_field_operators<amount_t> amount_t& operator/=(const amount_t& amt); // unary negation - void in_place_negate(); + amount_t operator-() const { + return negate(); + } amount_t negate() const { amount_t temp = *this; temp.in_place_negate(); return temp; } - amount_t operator-() const { - return negate(); + void in_place_negate(); + + // test for truth, zero and non-zero + operator bool() const { + return ! zero(); } - // test for zero and non-zero int sign() const; bool zero() const; bool realzero() const { return sign() == 0; } - operator bool() const { - return ! zero(); - } - // Methods relating to this amount's commodity + // conversion methods + string to_string() const; + string to_fullstring() const; + string quantity_string() const; + // methods relating to the commodity bool is_null() const { return ! quantity && ! has_commodity(); } @@ -205,40 +209,26 @@ class amount_t : public ordered_field_operators<amount_t> optional<moment_t> date() const; optional<string> tag() const; -#if 0 - // string and numeric conversions - operator string() const { - return to_string(); - } - operator long() const; - operator double() const; -#endif - - string to_string() const; - string to_fullstring() const; - string quantity_string() const; - // general methods amount_t round(unsigned int prec) const; amount_t round() const; amount_t unround() const; amount_t value(const moment_t& moment) const; + amount_t abs() const { if (sign() < 0) return negate(); return *this; } + amount_t reduce() const { amount_t temp(*this); temp.in_place_reduce(); return temp; } - - bool valid() const; - void in_place_reduce(); - static amount_t exact(const string& value); + bool valid() const; // This function is special, and exists only to support a custom // optimization in binary.cc (which offers a significant enough gain diff --git a/src/balance.cc b/src/balance.cc index e2e7df43..1baad2bf 100644 --- a/src/balance.cc +++ b/src/balance.cc @@ -2,6 +2,137 @@ namespace ledger { +balance_t& balance_t::operator*=(const balance_t& bal) +{ + if (realzero() || bal.realzero()) { + return *this = amount_t(); + } + 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; + + throw_(amount_error, "Cannot multiply two balances: " << temp << " * " << bal); + } +} + +balance_t& balance_t::operator*=(const amount_t& amt) +{ + if (realzero() || amt.realzero()) { + return *this = amount_t(); + } + 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) { + *this = (*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) { + 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); + } + } + return *this; +} + +balance_t& balance_t::operator/=(const balance_t& bal) +{ + if (bal.realzero()) { + throw_(amount_error, "Divide by zero: " << *this << " / " << bal); + } + else if (realzero()) { + return *this = amount_t(); + } + else if (bal.amounts.size() == 1) { + return *this /= (*bal.amounts.begin()).second; + } + else if (*this == bal) { + return *this = amount_t(1L); + } + else { + // Try stripping annotations before giving an error. + balance_t temp(bal.strip_annotations()); + if (temp.amounts.size() == 1) + return *this /= temp; + + throw_(amount_error, + "Cannot divide two balances: " << temp << " / " << bal); + } +} + +balance_t& balance_t::operator/=(const amount_t& amt) +{ + if (amt.realzero()) { + throw_(amount_error, "Divide by zero: " << *this << " / " << amt); + } + else if (realzero()) { + return *this = amount_t(); + } + 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; + + throw_(amount_error, "Attempt to divide balance by a commodity" << + " not found in that balance: " << temp << " * " << amt); + } + } + return *this; +} + amount_t balance_t::amount(const commodity_t& commodity) const { if (! commodity) { @@ -167,137 +298,6 @@ void balance_t::write(std::ostream& out, } } -balance_t& balance_t::operator*=(const balance_t& bal) -{ - if (realzero() || bal.realzero()) { - return *this = 0L; - } - 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; - - throw_(amount_error, "Cannot multiply two balances: " << temp << " * " << bal); - } -} - -balance_t& balance_t::operator*=(const amount_t& amt) -{ - 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) { - *this = (*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) { - 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); - } - } - return *this; -} - -balance_t& balance_t::operator/=(const balance_t& bal) -{ - if (bal.realzero()) { - throw_(amount_error, "Divide by zero: " << *this << " / " << bal); - } - 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; - } - else { - // Try stripping annotations before giving an error. - balance_t temp(bal.strip_annotations()); - if (temp.amounts.size() == 1) - return *this /= temp; - - throw_(amount_error, - "Cannot divide two balances: " << temp << " / " << bal); - } -} - -balance_t& balance_t::operator/=(const amount_t& amt) -{ - if (amt.realzero()) { - throw_(amount_error, "Divide by zero: " << *this << " / " << amt); - } - 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; - - throw_(amount_error, "Attempt to divide balance by a commodity" << - " not found in that balance: " << temp << " * " << amt); - } - } - return *this; -} - #if 0 balance_t::operator amount_t() const { diff --git a/src/balance.h b/src/balance.h index 2a81379b..38693bda 100644 --- a/src/balance.h +++ b/src/balance.h @@ -5,12 +5,12 @@ namespace ledger { +// jww (2007-05-01): What really should be the operational semantics +// of a balance? + class balance_t - : public totally_ordered<balance_t, - totally_ordered<balance_t, amount_t, - integer_arithmetic<balance_t, - integer_arithmetic<balance_t, amount_t - > > > > + : public ordered_field_operators<balance_t, + ordered_field_operators<balance_t, amount_t> > { public: typedef std::map<const commodity_t *, amount_t> amounts_map; @@ -54,10 +54,19 @@ public: } return *this; } - balance_t& operator=(const amount_t& amt) { - amounts.clear(); - *this += amt; - return *this; + + int compare(const balance_t& bal) const; + + 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(); } // in-place arithmetic @@ -68,15 +77,6 @@ public: *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.realzero()) - amounts.insert(amounts_pair(&amt.commodity(), amt)); - return *this; - } - balance_t& operator-=(const balance_t& bal) { for (amounts_map::const_iterator i = bal.amounts.begin(); i != bal.amounts.end(); @@ -84,25 +84,10 @@ public: *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; - if ((*i).second.realzero()) - amounts.erase(i); - } - else if (! amt.realzero()) { - amounts.insert(amounts_pair(&amt.commodity(), - amt)); - } - return *this; - } - - // multiplication and divide balance_t& operator*=(const balance_t& bal); - balance_t& operator*=(const amount_t& amt); - + balance_t& operator*=(const amount_t& amt); // special balance_t& operator/=(const balance_t& bal); - balance_t& operator/=(const amount_t& amt); + balance_t& operator/=(const amount_t& amt); // special // comparison bool operator<(const balance_t& bal) const { @@ -123,42 +108,6 @@ public: return true; } - bool operator<(const amount_t& amt) const { - if (amt.commodity()) - return amount(amt.commodity()) < amt; - - for (amounts_map::const_iterator i = amounts.begin(); - i != amounts.end(); - i++) - if ((*i).second < amt) - return true; - return false; - } - - int compare(const balance_t& bal) const; - - 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 { - if (amt.commodity()) - return amounts.size() == 1 && (*amounts.begin()).second == amt; - - for (amounts_map::const_iterator i = amounts.begin(); - i != amounts.end(); - i++) - if ((*i).second == amt) - return true; - return false; - } // unary negation void in_place_negate() { @@ -177,9 +126,6 @@ public: } // conversion operators -#if 0 - operator amount_t() const; -#endif operator bool() const { for (amounts_map::const_iterator i = amounts.begin(); i != amounts.end(); @@ -275,13 +221,9 @@ inline std::ostream& operator<<(std::ostream& out, const balance_t& bal) { } class balance_pair_t - : public totally_ordered<balance_pair_t, - totally_ordered<balance_pair_t, balance_t, - totally_ordered<balance_pair_t, amount_t, - integer_arithmetic<balance_pair_t, - integer_arithmetic<balance_pair_t, balance_t, - integer_arithmetic<balance_pair_t, amount_t - > > > > > > + : public ordered_field_operators<balance_pair_t, + ordered_field_operators<balance_pair_t, balance_t, + ordered_field_operators<balance_pair_t, amount_t> > > { balance_t quantity; optional<balance_t> cost; @@ -318,16 +260,6 @@ public: } return *this; } - balance_pair_t& operator=(const balance_t& bal) { - quantity = bal; - cost = optional<balance_t>(); - return *this; - } - balance_pair_t& operator=(const amount_t& amt) { - quantity = amt; - cost = optional<balance_t>(); - return *this; - } // in-place arithmetic balance_pair_t& operator+=(const balance_pair_t& bal_pair) { @@ -338,19 +270,6 @@ public: *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; - } - balance_pair_t& operator-=(const balance_pair_t& bal_pair) { if (bal_pair.cost && ! cost) cost = quantity; @@ -359,20 +278,6 @@ public: *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; - } - - // multiplication and division balance_pair_t& operator*=(const balance_pair_t& bal_pair) { if (bal_pair.cost && ! cost) cost = quantity; @@ -381,19 +286,6 @@ public: *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; - } - balance_pair_t& operator/=(const balance_pair_t& bal_pair) { if (bal_pair.cost && ! cost) cost = quantity; @@ -402,40 +294,13 @@ public: *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; - } // 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; - } - - int compare(const balance_pair_t& bal) const; - 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; + bool operator<(const balance_pair_t& bal_pair) const { + return quantity < bal_pair.quantity; } // unary negation @@ -454,14 +319,6 @@ public: } // test for non-zero (use ! for zero) -#if 0 - operator balance_t() const { - return quantity; - } - operator amount_t() const { - return quantity; - } -#endif operator bool() const { return quantity; } diff --git a/src/binary.cc b/src/binary.cc index 55d8e03a..5b57e171 100644 --- a/src/binary.cc +++ b/src/binary.cc @@ -175,7 +175,7 @@ inline void read_binary_transaction(char *& data, transaction_t * xact) repitem_t::wrap(xact, static_cast<repitem_t *>(xact->entry->data)); xact->data = item; - xact->amount = valexpr_t(xact->amount_expr).calc(item).to_amount(); + xact->amount = valexpr_t(xact->amount_expr).calc(item).amount(); } if (read_binary_bool(data)) { diff --git a/src/journal.cc b/src/journal.cc index 948d9b6a..109d07f4 100644 --- a/src/journal.cc +++ b/src/journal.cc @@ -145,15 +145,15 @@ bool entry_base_t::finalize() // the balance. This is done for the last eligible commodity. if (! saw_null && balance && balance.type == value_t::BALANCE && - ((balance_t *) balance.data)->amounts.size() == 2) { + balance.balance().amounts.size() == 2) { transactions_list::const_iterator x = transactions.begin(); assert((*x)->amount); commodity_t& this_comm = (*x)->amount->commodity(); balance_t::amounts_map::const_iterator this_bal = - ((balance_t *) balance.data)->amounts.find(&this_comm); + balance.balance().amounts.find(&this_comm); balance_t::amounts_map::const_iterator other_bal = - ((balance_t *) balance.data)->amounts.begin(); + balance.balance().amounts.begin(); if (this_bal == other_bal) other_bal++; @@ -196,7 +196,8 @@ bool entry_base_t::finalize() continue; if (! empty_allowed) - throw_(std::logic_error, "Only one transaction with null amount allowed per entry"); + throw_(std::logic_error, + "Only one transaction with null amount allowed per entry"); empty_allowed = false; // If one transaction gives no value at all, its value will become @@ -207,12 +208,12 @@ bool entry_base_t::finalize() balance_t * bal = NULL; switch (balance.type) { case value_t::BALANCE_PAIR: - bal = &((balance_pair_t *) balance.data)->quantity; + bal = &balance.balance_pair().quantity; // fall through... case value_t::BALANCE: if (! bal) - bal = (balance_t *) balance.data; + bal = &balance.balance(); if (bal->amounts.size() < 2) { balance.cast(value_t::AMOUNT); @@ -241,7 +242,7 @@ bool entry_base_t::finalize() // fall through... case value_t::AMOUNT: - (*x)->amount = ((amount_t *) balance.data)->negate(); + (*x)->amount = balance.amount().negate(); (*x)->flags |= TRANSACTION_CALCULATED; balance += *(*x)->amount; diff --git a/src/py_amount.cc b/src/py_amount.cc index e26ba35e..49d0c23b 100644 --- a/src/py_amount.cc +++ b/src/py_amount.cc @@ -87,12 +87,10 @@ void export_amount() .def(self += double()) .def(self + self) -#if 0 .def(self + long()) .def(long() + self) .def(self + double()) .def(double() + self) -#endif .def(self -= self) .def(self -= long()) diff --git a/src/pyinterp.cc b/src/pyinterp.cc index 0ab25cc3..c0e22740 100644 --- a/src/pyinterp.cc +++ b/src/pyinterp.cc @@ -117,11 +117,11 @@ void python_interpreter_t::functor_t::operator()(value_t& result, result = static_cast<const value_t&>(extract<value_t>(func.ptr())); } else { assert(locals->args.type == value_t::SEQUENCE); - if (locals->args.to_sequence()->size() > 0) { + if (locals->args.sequence()->size() > 0) { list arglist; for (value_t::sequence_t::iterator - i = locals->args.to_sequence()->begin(); - i != locals->args.to_sequence()->end(); + i = locals->args.sequence()->begin(); + i != locals->args.sequence()->end(); i++) arglist.append(*i); @@ -155,10 +155,10 @@ void python_interpreter_t::lambda_t::operator()(value_t& result, { try { assert(locals->args.type == value_t::SEQUENCE); - assert(locals->args.to_sequence()->size() == 1); + assert(locals->args.sequence()->size() == 1); value_t item = locals->args[0]; assert(item.type == value_t::POINTER); - result = call<value_t>(func.ptr(), (xml::node_t *)*(void **)item.data); + result = call<value_t>(func.ptr(), item.xml_node()); } catch (const error_already_set&) { PyErr_Print(); diff --git a/src/report.cc b/src/report.cc index 2d49b62b..65ceabd1 100644 --- a/src/report.cc +++ b/src/report.cc @@ -20,16 +20,16 @@ void report_t::abbrev(value_t& result, xml::xpath_t::scope_t * locals) if (locals->args.size() < 2) throw_(std::logic_error, "usage: abbrev(STRING, WIDTH [, STYLE, ABBREV_LEN])"); - string str = locals->args[0].to_string(); + string str = locals->args[0].string_value(); long wid = locals->args[1]; elision_style_t style = session->elision_style; if (locals->args.size() == 3) - style = (elision_style_t)locals->args[2].to_integer(); + style = (elision_style_t)locals->args[2].integer(); long abbrev_len = session->abbrev_length; if (locals->args.size() == 4) - abbrev_len = locals->args[3].to_integer(); + abbrev_len = locals->args[3].integer(); result.set_string(abbreviate(str, wid, style, true, (int)abbrev_len)); } @@ -39,11 +39,11 @@ void report_t::ftime(value_t&, xml::xpath_t::scope_t * locals) if (locals->args.size() < 1) throw_(std::logic_error, "usage: ftime(DATE [, DATE_FORMAT])"); - moment_t date = locals->args[0].to_datetime(); + moment_t date = locals->args[0].datetime(); string date_format; if (locals->args.size() == 2) - date_format = locals->args[1].to_string(); + date_format = locals->args[1].string_value(); #if 0 // jww (2007-04-18): Need to setup an output facet here else diff --git a/src/report.h b/src/report.h index ca066566..21ee261f 100644 --- a/src/report.h +++ b/src/report.h @@ -60,18 +60,18 @@ class report_t : public xml::xpath_t::scope_t xml::xpath_t(expr).compile((xml::document_t *)NULL, this); } void option_eval(value_t&, xml::xpath_t::scope_t * locals) { - eval(locals->args[0].to_string()); + eval(locals->args[0].string_value()); } void option_amount(value_t&, xml::xpath_t::scope_t * locals) { - eval(string("t=") + locals->args[0].to_string()); + eval(string("t=") + locals->args[0].string_value()); } void option_total(value_t&, xml::xpath_t::scope_t * locals) { - eval(string("T()=") + locals->args[0].to_string()); + eval(string("T()=") + locals->args[0].string_value()); } void option_format(value_t&, xml::xpath_t::scope_t * locals) { - format_string = locals->args[0].to_string(); + format_string = locals->args[0].string_value(); } void option_raw(value_t&) { diff --git a/src/session.h b/src/session.h index 1a28e6ee..6fb2c21d 100644 --- a/src/session.h +++ b/src/session.h @@ -170,7 +170,7 @@ class session_t : public xml::xpath_t::scope_t // void option_file(value_t&, xml::xpath_t::scope_t * locals) { - data_file = locals->args.to_string(); + data_file = locals->args.string_value(); } #if 0 diff --git a/src/textual.cc b/src/textual.cc index e464f9c3..da7cfbd6 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -66,7 +66,7 @@ parse_amount_expr(std::istream& in, journal_t *, } #endif - amount = xpath.calc(static_cast<xml::transaction_node_t *>(xact.data)).to_amount(); + amount = xpath.calc(static_cast<xml::transaction_node_t *>(xact.data)).amount(); DEBUG("ledger.textual.parse", "line " << linenum << ": " << "The transaction amount is " << amount); diff --git a/src/value.cc b/src/value.cc index accc5739..d5d4e655 100644 --- a/src/value.cc +++ b/src/value.cc @@ -3,84 +3,93 @@ namespace ledger { -bool value_t::to_boolean() const +bool& value_t::boolean() { if (type == BOOLEAN) { return *(bool *) data; } else { + throw_(value_error, "Value is not a boolean"); value_t temp(*this); temp.in_place_cast(BOOLEAN); return *(bool *) temp.data; } } -long value_t::to_integer() const +long& value_t::integer() { if (type == INTEGER) { return *(long *) data; } else { + throw_(value_error, "Value is not an integer"); value_t temp(*this); temp.in_place_cast(INTEGER); return *(long *) temp.data; } } -moment_t value_t::to_datetime() const +moment_t& value_t::datetime() { if (type == DATETIME) { return *(moment_t *) data; } else { + throw_(value_error, "Value is not a date/time"); value_t temp(*this); temp.in_place_cast(DATETIME); return *(moment_t *) temp.data; } } -amount_t value_t::to_amount() const +amount_t& value_t::amount() { if (type == AMOUNT) { return *(amount_t *) data; } else { + throw_(value_error, "Value is not an amount"); value_t temp(*this); temp.in_place_cast(AMOUNT); return *(amount_t *) temp.data; } } -balance_t value_t::to_balance() const +balance_t& value_t::balance() { if (type == BALANCE) { return *(balance_t *) data; } else { + throw_(value_error, "Value is not a balance"); value_t temp(*this); temp.in_place_cast(BALANCE); return *(balance_t *) temp.data; } } -balance_pair_t value_t::to_balance_pair() const +balance_pair_t& value_t::balance_pair() { if (type == BALANCE_PAIR) { return *(balance_pair_t *) data; } else { + throw_(value_error, "Value is not a balance pair"); value_t temp(*this); temp.in_place_cast(BALANCE_PAIR); return *(balance_pair_t *) temp.data; } } -string value_t::to_string() const +string& value_t::string_value() { if (type == STRING) { return **(string **) data; } else { + throw_(value_error, "Value is not a string"); +#if 0 std::ostringstream out; out << *this; return out.str(); +#endif } } -xml::node_t * value_t::to_xml_node() const +xml::node_t *& value_t::xml_node() { if (type == XML_NODE) return *(xml::node_t **) data; @@ -88,7 +97,7 @@ xml::node_t * value_t::to_xml_node() const throw_(value_error, "Value is not an XML node"); } -void * value_t::to_pointer() const +void *& value_t::pointer() { if (type == POINTER) return *(void **) data; @@ -96,7 +105,7 @@ void * value_t::to_pointer() const throw_(value_error, "Value is not a pointer"); } -value_t::sequence_t * value_t::to_sequence() const +value_t::sequence_t *& value_t::sequence() { if (type == SEQUENCE) return *(sequence_t **) data; @@ -352,7 +361,7 @@ value_t& value_t::operator+=(const value_t& val) case BALANCE: switch (val.type) { case INTEGER: - *((balance_t *) data) += *((long *) val.data); + *((balance_t *) data) += amount_t(*((long *) val.data)); break; case AMOUNT: *((balance_t *) data) += *((amount_t *) val.data); @@ -375,7 +384,7 @@ value_t& value_t::operator+=(const value_t& val) case BALANCE_PAIR: switch (val.type) { case INTEGER: - *((balance_pair_t *) data) += *((long *) val.data); + *((balance_pair_t *) data) += amount_t(*((long *) val.data)); break; case AMOUNT: *((balance_pair_t *) data) += *((amount_t *) val.data); @@ -536,7 +545,7 @@ value_t& value_t::operator-=(const value_t& val) case BALANCE: switch (val.type) { case INTEGER: - *((balance_t *) data) -= *((long *) val.data); + *((balance_t *) data) -= amount_t(*((long *) val.data)); break; case AMOUNT: *((balance_t *) data) -= *((amount_t *) val.data); @@ -557,7 +566,7 @@ value_t& value_t::operator-=(const value_t& val) case BALANCE_PAIR: switch (val.type) { case INTEGER: - *((balance_pair_t *) data) -= *((long *) val.data); + *((balance_pair_t *) data) -= amount_t(*((long *) val.data)); break; case AMOUNT: *((balance_pair_t *) data) -= *((amount_t *) val.data); @@ -686,7 +695,7 @@ value_t& value_t::operator*=(const value_t& val) case BALANCE_PAIR: switch (val.type) { case INTEGER: - *((balance_pair_t *) data) *= *((long *) val.data); + *((balance_pair_t *) data) *= amount_t(*((long *) val.data)); break; case AMOUNT: *((balance_pair_t *) data) *= *((amount_t *) val.data); @@ -833,7 +842,7 @@ value_t& value_t::operator/=(const value_t& val) case BALANCE_PAIR: switch (val.type) { case INTEGER: - *((balance_pair_t *) data) /= *((long *) val.data); + *((balance_pair_t *) data) /= amount_t(*((long *) val.data)); break; case AMOUNT: *((balance_pair_t *) data) /= *((amount_t *) val.data); @@ -884,7 +893,7 @@ value_t::operator bool() const case STRING: return ! (**((string **) data)).empty(); case XML_NODE: - return (*(xml::node_t **) data)->to_value().to_boolean(); + return (*(xml::node_t **) data)->to_value().boolean(); case POINTER: return *(void **) data != NULL; case SEQUENCE: @@ -1032,10 +1041,18 @@ value_t::operator string() const } #endif -inline int compare_bool(const bool left, const bool right) { +template <typename T> +inline int compare_bool(const T& left, const T& right) { return (! left && right ? -1 : (left && ! right ? 1 : 0)); } +// jww (2007-05-01): This is going to be slow as hell for two +// balance_t objects +template <typename T> +inline int compare_equality(const T& left, const T& right) { + return (left < right ? -1 : (left > right ? 1 : 0)); +} + int value_t::compare(const value_t& val) const { if (val.type == XML_NODE) @@ -1090,10 +1107,12 @@ int value_t::compare(const value_t& val) const return amount_t(*((long *) data)).compare(*((amount_t *) val.data)); case BALANCE: - return balance_t(*((long *) data)).compare(*((balance_t *) val.data)); + return compare_equality(balance_t(*((long *) data)), + *((balance_t *) val.data)); case BALANCE_PAIR: - return balance_pair_t(*((long *) data)).compare(*((balance_pair_t *) val.data)); + return compare_equality(balance_pair_t(*((long *) data)), + *((balance_pair_t *) val.data)); case STRING: throw_(value_error, "Cannot compare an integer to a string"); @@ -1116,8 +1135,7 @@ int value_t::compare(const value_t& val) const throw_(value_error, "Cannot compare a date/time to an integer"); case DATETIME: - return (*((moment_t *) data) < *((moment_t *) val.data) ? -1 : - (*((moment_t *) data) > *((moment_t *) val.data) ? 1 : 0)); + return compare_equality(*((moment_t *) data), *((moment_t *) val.data)); case AMOUNT: throw_(value_error, "Cannot compare a date/time to an amount"); @@ -1153,10 +1171,12 @@ int value_t::compare(const value_t& val) const return ((amount_t *) data)->compare(*((amount_t *) val.data)); case BALANCE: - return balance_t(*((amount_t *) data)).compare(*((balance_t *) val.data)); + return compare_equality(balance_t(*((amount_t *) data)), + *((balance_t *) val.data)); case BALANCE_PAIR: - return balance_pair_t(*((amount_t *) data)).compare(*((balance_pair_t *) val.data)); + return compare_equality(balance_pair_t(*((amount_t *) data)), + *((balance_pair_t *) val.data)); case STRING: throw_(value_error, "Cannot compare an amount to a string"); @@ -1177,20 +1197,22 @@ int value_t::compare(const value_t& val) const throw_(value_error, "Cannot compare a balance to a boolean"); case INTEGER: - return ((balance_t *) data)->compare(amount_t(*((long *) val.data))); + return compare_equality(*(balance_t *) data, + balance_t(*((long *) val.data))); case DATETIME: throw_(value_error, "Cannot compare a balance to a date/time"); case AMOUNT: - return ((balance_t *) data)->compare(*((amount_t *) val.data)); + return compare_equality(*(balance_t *) data, + balance_t(*((amount_t *) val.data))); case BALANCE: - return ((balance_t *) data)->compare(*((balance_t *) val.data)); + return compare_equality(*(balance_t *) data, *((balance_t *) val.data)); case BALANCE_PAIR: - return balance_pair_t(*((balance_t *) data)). - compare(((balance_pair_t *) val.data)->quantity); + return compare_equality(balance_pair_t(*((balance_t *) data)), + *(balance_pair_t *) val.data); case STRING: throw_(value_error, "Cannot compare a balance to a string"); @@ -1211,19 +1233,23 @@ int value_t::compare(const value_t& val) const throw_(value_error, "Cannot compare a balance pair to a boolean"); case INTEGER: - return ((balance_pair_t *) data)->compare(amount_t(*((long *) val.data))); + return compare_equality(*(balance_pair_t *) data, + balance_pair_t(amount_t(*((long *) val.data)))); case DATETIME: throw_(value_error, "Cannot compare a balance pair to a date/time"); case AMOUNT: - return ((balance_pair_t *) data)->compare(*((amount_t *) val.data)); + return compare_equality(*(balance_pair_t *) data, + balance_pair_t(*((amount_t *) val.data))); case BALANCE: - return ((balance_pair_t *) data)->compare(*((balance_t *) val.data)); + return compare_equality(*(balance_pair_t *) data, + balance_pair_t(*((balance_t *) val.data))); case BALANCE_PAIR: - return ((balance_pair_t *) data)->compare(*((balance_pair_t *) val.data)); + return compare_equality(*(balance_pair_t *) data, + *((balance_pair_t *) val.data)); case STRING: throw_(value_error, "Cannot compare a balance pair to a string"); diff --git a/src/value.h b/src/value.h index 30cea4a0..b44cdd33 100644 --- a/src/value.h +++ b/src/value.h @@ -19,13 +19,20 @@ namespace xml { // fact that logic chains only need boolean values to continue, no // memory allocations need to take place at all. -class value_t : public ordered_field_operators<value_t> +class value_t + : public ordered_field_operators<value_t, + ordered_field_operators<value_t, balance_pair_t, + ordered_field_operators<value_t, balance_t, + ordered_field_operators<value_t, amount_t, + ordered_field_operators<value_t, double, + ordered_field_operators<value_t, unsigned long, + ordered_field_operators<value_t, long> > > > > > > { + char data[sizeof(balance_pair_t)]; + public: typedef std::vector<value_t> sequence_t; - char data[sizeof(balance_pair_t)]; - enum type_t { BOOLEAN, INTEGER, @@ -124,6 +131,7 @@ class value_t : public ordered_field_operators<value_t> void simplify(); value_t& operator=(const value_t& val); +#if 0 value_t& operator=(const bool val) { if ((bool *) data != &val) { destroy(); @@ -258,6 +266,7 @@ class value_t : public ordered_field_operators<value_t> return *this; } } +#endif value_t& set_string(const string& str = "") { if (type != STRING) { @@ -270,31 +279,31 @@ class value_t : public ordered_field_operators<value_t> return *this; } - bool to_boolean() const; - long to_integer() const; - moment_t to_datetime() const; - amount_t to_amount() const; - balance_t to_balance() const; - balance_pair_t to_balance_pair() const; - string to_string() const; - xml::node_t * to_xml_node() const; - void * to_pointer() const; - sequence_t * to_sequence() const; + bool& boolean(); + long& integer(); + moment_t& datetime(); + amount_t& amount(); + balance_t& balance(); + balance_pair_t& balance_pair(); + string& string_value(); + xml::node_t *& xml_node(); + void *& pointer(); + sequence_t *& sequence(); value_t& operator[](const int index) { - sequence_t * seq = to_sequence(); + sequence_t * seq = sequence(); assert(seq); return (*seq)[index]; } void push_back(const value_t& val) { - sequence_t * seq = to_sequence(); + sequence_t * seq = sequence(); assert(seq); return seq->push_back(val); } std::size_t size() const { - sequence_t * seq = to_sequence(); + sequence_t * seq = const_cast<value_t&>(*this).sequence(); assert(seq); return seq->size(); } @@ -309,18 +318,22 @@ class value_t : public ordered_field_operators<value_t> bool operator==(const value_t& val) const { return compare(val) == 0; } +#if 0 template <typename T> bool operator==(const T& val) const { return *this == value_t(val); } +#endif bool operator<(const value_t& val) const { return compare(val) < 0; } +#if 0 template <typename T> bool operator<(const T& val) const { return *this < value_t(val); } +#endif operator bool() const; @@ -336,15 +349,15 @@ class value_t : public ordered_field_operators<value_t> operator balance_pair_t() const; #endif - void in_place_negate(); + value_t operator-() const { + return negate(); + } value_t negate() const { value_t temp = *this; temp.in_place_negate(); return temp; } - value_t operator-() const { - return negate(); - } + void in_place_negate(); bool realzero() const; value_t abs() const; @@ -380,6 +393,8 @@ class value_t : public ordered_field_operators<value_t> void write(std::ostream& out, const int first_width, const int latter_width = -1) const; + + friend std::ostream& operator<<(std::ostream& out, const value_t& val); }; #if 0 diff --git a/src/xpath.cc b/src/xpath.cc index 53d337ea..1dabd871 100644 --- a/src/xpath.cc +++ b/src/xpath.cc @@ -534,7 +534,7 @@ bool xpath_t::function_scope_t::resolve(const string& name, case 't': if (name == "text") { if (value->type == value_t::XML_NODE) - result.set_string(value->to_xml_node()->text()); + result.set_string(value->xml_node()->text()); else throw_(calc_error, "Attempt to call text() on a non-node value"); return true; @@ -650,7 +650,7 @@ xpath_t::parse_value_term(std::istream& in, unsigned short tflags) const #endif /* USE_BOOST_PYTHON */ #endif - string ident = tok.value.to_string(); + string ident = tok.value.string_value(); int id = -1; if (std::isdigit(ident[0])) { node.reset(new op_t(op_t::ARG_INDEX)); @@ -692,7 +692,7 @@ xpath_t::parse_value_term(std::istream& in, unsigned short tflags) const throw_(parse_error, "@ symbol must be followed by attribute name"); node.reset(new op_t(op_t::ATTR_NAME)); - node->name = new string(tok.value.to_string()); + node->name = new string(tok.value.string_value()); break; #if 0 @@ -1184,7 +1184,7 @@ void xpath_t::op_t::find_values(value_t * context, scope_t * scope, if (recursive) { if (context->type == value_t::XML_NODE) { - node_t * ptr = context->to_xml_node(); + node_t * ptr = context->xml_node(); if (ptr->flags & XML_NODE_IS_PARENT) { parent_node_t * parent = static_cast<parent_node_t *>(ptr); for (node_t * node = parent->children(); @@ -1211,10 +1211,10 @@ bool xpath_t::op_t::test_value(value_t * context, scope_t * scope, switch (expr->valuep->type) { case value_t::INTEGER: case value_t::AMOUNT: - return *expr->valuep == (long)index + 1; + return *expr->valuep == value_t((long)index + 1); default: - return expr->valuep->to_boolean(); + return expr->valuep->boolean(); } } @@ -1246,7 +1246,7 @@ xpath_t::op_t * xpath_t::op_t::defer_sequence(value_t::sequence_t& result_seq) if ((*i).type != value_t::POINTER) *opp = wrap_value(*i)->acquire(); else - *opp = static_cast<op_t *>((*i).to_pointer()); + *opp = static_cast<op_t *>((*i).pointer()); } return lit_seq.release(); @@ -1256,7 +1256,7 @@ void xpath_t::op_t::append_value(value_t& val, value_t::sequence_t& result_seq) { if (val.type == value_t::SEQUENCE) { - value_t::sequence_t * subseq = val.to_sequence(); + value_t::sequence_t * subseq = val.sequence(); for (value_t::sequence_t::iterator i = subseq->begin(); i != subseq->end(); i++) @@ -1284,8 +1284,8 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope, case document_t::PARENT: if (context->type != value_t::XML_NODE) throw_(compile_error, "Referencing parent node from a non-node value"); - else if (context->to_xml_node()->parent) - return wrap_value(context->to_xml_node()->parent)->acquire(); + else if (context->xml_node()->parent) + return wrap_value(context->xml_node()->parent)->acquire(); else throw_(compile_error, "Referencing parent node from the root node"); @@ -1293,13 +1293,13 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope, if (context->type != value_t::XML_NODE) throw_(compile_error, "Referencing root node from a non-node value"); else - return wrap_value(context->to_xml_node()->document->top)->acquire(); + return wrap_value(context->xml_node()->document->top)->acquire(); case document_t::ALL: { if (context->type != value_t::XML_NODE) throw_(compile_error, "Referencing child nodes from a non-node value"); - node_t * ptr = context->to_xml_node(); + node_t * ptr = context->xml_node(); if (! (ptr->flags & XML_NODE_IS_PARENT)) throw_(compile_error, "Request for child nodes of a leaf node"); @@ -1319,7 +1319,7 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope, case NODE_NAME: if (context->type == value_t::XML_NODE) { - node_t * ptr = context->to_xml_node(); + node_t * ptr = context->xml_node(); if (resolve) { // First, look up the symbol as a node name within the current // context. If any exist, then return the set of names. @@ -1352,7 +1352,7 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope, case ATTR_NAME: { // jww (2006-09-29): Attrs should map strings to values, not strings - const char * value = context->to_xml_node()->get_attr(name->c_str()); + const char * value = context->xml_node()->get_attr(name->c_str()); return wrap_value(value)->acquire(); } @@ -1372,8 +1372,8 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope, case ARG_INDEX: if (scope && scope->kind == scope_t::ARGUMENT) { assert(scope->args.type == value_t::SEQUENCE); - if (arg_index < scope->args.to_sequence()->size()) - return wrap_value((*scope->args.to_sequence())[arg_index])->acquire(); + if (arg_index < scope->args.sequence()->size()) + return wrap_value((*scope->args.sequence())[arg_index])->acquire(); else throw_(compile_error, "Reference to non-existing argument"); } else { @@ -1815,7 +1815,7 @@ xpath_t::op_t * xpath_t::op_t::compile(value_t * context, scope_t * scope, } case value_t::SEQUENCE: { - value_t::sequence_t * seq = lexpr->valuep->to_sequence(); + value_t::sequence_t * seq = lexpr->valuep->sequence(); int index = 0; for (value_t::sequence_t::iterator i = seq->begin(); diff --git a/src/xpath.h b/src/xpath.h index 638ec482..16790e2b 100644 --- a/src/xpath.h +++ b/src/xpath.h @@ -760,7 +760,7 @@ inline std::ostream& operator<<(std::ostream& out, const xpath_t::op_t& op) { template <typename T> inline T * get_ptr(xml::xpath_t::scope_t * locals, unsigned int idx) { assert(locals->args.size() > idx); - T * ptr = static_cast<T *>(locals->args[idx].to_pointer()); + T * ptr = static_cast<T *>(locals->args[idx].pointer()); assert(ptr); return ptr; } |