More work to use boost/operators.hpp.

This commit is contained in:
John Wiegley 2007-05-02 03:04:40 +00:00
parent 230e03166f
commit 76b2066b8b
16 changed files with 319 additions and 523 deletions

View file

@ -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) {

View file

@ -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

View file

@ -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
{

View file

@ -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;
}

View file

@ -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)) {

View file

@ -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;

View file

@ -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())

View file

@ -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();

View file

@ -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

View file

@ -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&) {

View file

@ -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

View file

@ -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);

View file

@ -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");

View file

@ -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

View file

@ -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();

View file

@ -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;
}