summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2004-08-17 22:18:38 -0400
committerJohn Wiegley <johnw@newartisans.com>2004-08-17 22:18:38 -0400
commit55d58940ceb6a47e4032bbad83909d1ca82d2e03 (patch)
tree3cf5414137af9893924bedc3c6ad8c9f48a8084b
parent18ec7d05391d55a804042f47882c5af4e5765e86 (diff)
downloadfork-ledger-55d58940ceb6a47e4032bbad83909d1ca82d2e03.tar.gz
fork-ledger-55d58940ceb6a47e4032bbad83909d1ca82d2e03.tar.bz2
fork-ledger-55d58940ceb6a47e4032bbad83909d1ca82d2e03.zip
speed improvements; my "bal" script is cut to a third
-rw-r--r--amount.cc92
-rw-r--r--amount.h25
-rw-r--r--balance.h37
-rw-r--r--valexpr.cc110
-rw-r--r--valexpr.h30
-rw-r--r--value.h995
6 files changed, 1206 insertions, 83 deletions
diff --git a/amount.cc b/amount.cc
index a8f128cf..1ba5da7f 100644
--- a/amount.cc
+++ b/amount.cc
@@ -254,16 +254,25 @@ amount_t& amount_t::negate()
return *this;
}
-// comparisons to zero
+// integer comparisons
+template <typename T>
+static inline void parse_num(amount_t& amt, T num) {
+ std::string str;
+ { std::ostringstream strstr(str);
+ strstr << num;
+ }
+ { std::istringstream strstr(str);
+ amt.parse(strstr);
+ }
+}
+
bool amount_t::operator<(const int num) const
{
if (num == 0) {
return quantity ? mpz_sgn(MPZ(quantity)) < 0 : false;
} else {
- std::string str;
- std::ostringstream strstr(str);
- strstr << num;
- amount_t amt(strstr.str());
+ amount_t amt;
+ parse_num(amt, num);
return *this < amt;
}
}
@@ -273,10 +282,8 @@ bool amount_t::operator<=(const int num) const
if (num == 0) {
return quantity ? mpz_sgn(MPZ(quantity)) <= 0 : true;
} else {
- std::string str;
- std::ostringstream strstr(str);
- strstr << num;
- amount_t amt(strstr.str());
+ amount_t amt;
+ parse_num(amt, num);
return *this <= amt;
}
}
@@ -286,10 +293,8 @@ bool amount_t::operator>(const int num) const
if (num == 0) {
return quantity ? mpz_sgn(MPZ(quantity)) > 0 : false;
} else {
- std::string str;
- std::ostringstream strstr(str);
- strstr << num;
- amount_t amt(strstr.str());
+ amount_t amt;
+ parse_num(amt, num);
return *this > amt;
}
}
@@ -299,14 +304,67 @@ bool amount_t::operator>=(const int num) const
if (num == 0) {
return quantity ? mpz_sgn(MPZ(quantity)) >= 0 : true;
} else {
- std::string str;
- std::ostringstream strstr(str);
- strstr << num;
- amount_t amt(strstr.str());
+ amount_t amt;
+ parse_num(amt, num);
return *this >= amt;
}
}
+bool amount_t::operator<(const unsigned int num) const
+{
+ if (num == 0) {
+ return quantity ? mpz_sgn(MPZ(quantity)) < 0 : false;
+ } else {
+ amount_t amt;
+ parse_num(amt, num);
+ return *this < amt;
+ }
+}
+
+bool amount_t::operator<=(const unsigned int num) const
+{
+ if (num == 0) {
+ return quantity ? mpz_sgn(MPZ(quantity)) <= 0 : true;
+ } else {
+ amount_t amt;
+ parse_num(amt, num);
+ return *this <= amt;
+ }
+}
+
+bool amount_t::operator>(const unsigned int num) const
+{
+ if (num == 0) {
+ return quantity ? mpz_sgn(MPZ(quantity)) > 0 : false;
+ } else {
+ amount_t amt;
+ parse_num(amt, num);
+ return *this > amt;
+ }
+}
+
+bool amount_t::operator>=(const unsigned int num) const
+{
+ if (num == 0) {
+ return quantity ? mpz_sgn(MPZ(quantity)) >= 0 : true;
+ } else {
+ amount_t amt;
+ parse_num(amt, num);
+ return *this >= amt;
+ }
+}
+
+bool amount_t::operator==(const unsigned int num) const
+{
+ if (num == 0) {
+ return quantity ? mpz_sgn(MPZ(quantity)) == 0 : true;
+ } else {
+ amount_t amt;
+ parse_num(amt, num);
+ return *this == amt;
+ }
+}
+
// comparisons between amounts
bool amount_t::operator<(const amount_t& amt) const
{
diff --git a/amount.h b/amount.h
index 5e31d95f..c94b5dc1 100644
--- a/amount.h
+++ b/amount.h
@@ -41,15 +41,10 @@ class amount_t
commodity = amt.commodity;
}
amount_t(const std::string& value) {
- _init();
- std::istringstream str(value);
- str >> *this;
+ parse(value);
}
amount_t(const char * value) {
- _init();
- std::string valstr(value);
- std::istringstream str(valstr);
- str >> *this;
+ parse(value);
}
amount_t(const bool value);
amount_t(const int value);
@@ -122,12 +117,21 @@ class amount_t
// test for non-zero (use ! for zero)
operator bool() const;
- // comparisons to zero
+ // integer comparisons
bool operator<(const int num) const;
bool operator<=(const int num) const;
bool operator>(const int num) const;
bool operator>=(const int num) const;
+ bool operator<(const unsigned int num) const;
+ bool operator<=(const unsigned int num) const;
+ bool operator>(const unsigned int num) const;
+ bool operator>=(const unsigned int num) const;
+ bool operator==(const unsigned int num) const;
+ bool operator!=(const unsigned int num) const {
+ return ! (*this == num);
+ }
+
// comparisons between amounts
bool operator<(const amount_t& amt) const;
bool operator<=(const amount_t& amt) const;
@@ -142,6 +146,11 @@ class amount_t
amount_t value(const std::time_t moment) const;
+ void abs() {
+ if (*this < 0)
+ negate();
+ }
+
operator std::string() const;
void parse(std::istream& in);
diff --git a/balance.h b/balance.h
index 5390a15e..53c533e9 100644
--- a/balance.h
+++ b/balance.h
@@ -243,6 +243,12 @@ class balance_t
bool operator<=(const amount_t& amt) const {
return amount(amt.commodity) <= amt;
}
+ bool operator<(const unsigned int val) const {
+ return amount() < val;
+ }
+ bool operator<=(const unsigned int val) const {
+ return amount() <= val;
+ }
bool operator>(const balance_t& bal) const {
for (amounts_map::const_iterator i = bal.amounts.begin();
@@ -283,6 +289,12 @@ class balance_t
bool operator>=(const amount_t& amt) const {
return amount(amt.commodity) >= amt;
}
+ bool operator>(const unsigned int val) const {
+ return amount() > val;
+ }
+ bool operator>=(const unsigned int val) const {
+ return amount() >= val;
+ }
bool operator==(const balance_t& bal) const {
amounts_map::const_iterator i, j;
@@ -298,12 +310,18 @@ class balance_t
bool operator==(const amount_t& amt) const {
return amounts.size() == 1 && (*amounts.begin()).second == amt;
}
+ bool operator==(const unsigned int val) const {
+ return amount() == val;
+ }
bool operator!=(const balance_t& bal) const {
return ! (*this == bal);
}
bool operator!=(const amount_t& amt) const {
return ! (*this == amt);
}
+ bool operator!=(const unsigned int val) const {
+ return ! (*this == val);
+ }
// unary negation
balance_t& negate() {
@@ -322,7 +340,10 @@ class balance_t
return negated();
}
- // test for non-zero (use ! for zero)
+ // conversion operators
+ operator amount_t() const {
+ return amount();
+ }
operator bool() const {
for (amounts_map::const_iterator i = amounts.begin();
i != amounts.end();
@@ -338,14 +359,18 @@ class balance_t
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();
+ }
};
inline balance_t abs(const balance_t& bal) {
- balance_t temp;
- for (amounts_map::const_iterator i = bal.amounts.begin();
- i != bal.amounts.end();
- i++)
- temp += abs((*i).second);
+ balance_t temp = bal;
+ temp.abs();
return temp;
}
diff --git a/valexpr.cc b/valexpr.cc
index febc47fe..7c97451f 100644
--- a/valexpr.cc
+++ b/valexpr.cc
@@ -60,17 +60,21 @@ mask_t::~mask_t() {
}
-void value_expr_t::compute(balance_t& result, const details_t& details) const
+void value_expr_t::compute(value_t& result, const details_t& details,
+ value_t::type_t type) const
{
- switch (type) {
- case CONSTANT_A:
- result = constant_a;
+ switch (kind) {
+ case CONSTANT_I:
+ result = constant_i;
break;
-
case CONSTANT_T:
result = (unsigned int) constant_t;
break;
+ case CONSTANT_A:
+ result = constant_a;
+ break;
+
case AMOUNT:
if (details.xact)
result = details.xact->amount;
@@ -183,11 +187,15 @@ void value_expr_t::compute(balance_t& result, const details_t& details) const
case INDEX:
if (details.xact)
result = details.xact->index + 1;
+ else
+ result = 0U;
break;
case DEPTH:
if (details.account)
- result = details.account->depth - 1;
+ result = (unsigned int) (details.account->depth - 1);
+ else
+ result = 0U;
break;
case F_ARITH_MEAN:
@@ -212,15 +220,21 @@ void value_expr_t::compute(balance_t& result, const details_t& details) const
case F_ABS:
assert(left);
left->compute(result, details);
- result = abs(result);
+ result.abs();
break;
case F_STRIP: {
assert(left);
left->compute(result, details);
- amount_t amt = result.amount();
- amt.commodity = commodity_t::null_commodity;
- result = amt;
+ if (result.type == value_t::BALANCE) {
+ // jww (2004-08-17): do something smarter here
+ result.cast(value_t::AMOUNT);
+ }
+ if (result.type == value_t::AMOUNT) {
+ amount_t amt = result;
+ amt.commodity = commodity_t::null_commodity;
+ result = amt;
+ }
break;
}
@@ -244,11 +258,11 @@ void value_expr_t::compute(balance_t& result, const details_t& details) const
case F_VALUE: {
assert(left);
- left->compute(result, details);
+ left->compute(result, details, value_t::BALANCE);
std::time_t moment = now;
if (right) {
- switch (right->type) {
+ switch (right->kind) {
case DATE:
if (details.entry)
moment = details.entry->date;
@@ -262,20 +276,20 @@ void value_expr_t::compute(balance_t& result, const details_t& details) const
throw compute_error("Invalid date passed to P(value,date)");
}
}
- result = result.value(moment);
+ result = (*((balance_t *)result.data)).value(moment);
break;
}
case O_NOT:
- left->compute(result, details);
- result = result ? false : true;
+ left->compute(result, details, value_t::BOOLEAN);
+ result.negate();
break;
case O_QUES:
assert(left);
assert(right);
- assert(right->type == O_COL);
- left->compute(result, details);
+ assert(right->kind == O_COL);
+ left->compute(result, details, value_t::BOOLEAN);
if (result)
right->left->compute(result, details);
else
@@ -285,17 +299,17 @@ void value_expr_t::compute(balance_t& result, const details_t& details) const
case O_AND:
assert(left);
assert(right);
- left->compute(result, details);
+ left->compute(result, details, value_t::BOOLEAN);
if (result)
- right->compute(result, details);
+ right->compute(result, details, value_t::BOOLEAN);
break;
case O_OR:
assert(left);
assert(right);
- left->compute(result, details);
+ left->compute(result, details, value_t::BOOLEAN);
if (! result)
- right->compute(result, details);
+ right->compute(result, details, value_t::BOOLEAN);
break;
case O_EQ:
@@ -305,10 +319,10 @@ void value_expr_t::compute(balance_t& result, const details_t& details) const
case O_GTE: {
assert(left);
assert(right);
- balance_t temp;
+ value_t temp;
left->compute(temp, details);
right->compute(result, details);
- switch (type) {
+ switch (kind) {
case O_EQ: result = temp == result; break;
case O_LT: result = temp < result; break;
case O_LTE: result = temp <= result; break;
@@ -325,10 +339,10 @@ void value_expr_t::compute(balance_t& result, const details_t& details) const
case O_DIV: {
assert(left);
assert(right);
- balance_t temp;
+ value_t temp;
right->compute(temp, details);
left->compute(result, details);
- switch (type) {
+ switch (kind) {
case O_ADD: result += temp; break;
case O_SUB: result -= temp; break;
case O_MUL: result *= temp; break;
@@ -343,6 +357,9 @@ void value_expr_t::compute(balance_t& result, const details_t& details) const
assert(0);
break;
}
+
+ if (type < value_t::ANY && type != result.type)
+ result.cast(type);
}
value_expr_t * parse_value_term(std::istream& in);
@@ -357,18 +374,22 @@ value_expr_t * parse_value_term(std::istream& in)
value_expr_t * node = NULL;
char c = peek_next_nonws(in);
- if (std::isdigit(c) || c == '.' || c == '{') {
+ if (std::isdigit(c)) {
+ static char buf[2048];
+ READ_INTO(in, buf, 2048, c, std::isdigit(c));
+
+ node = new value_expr_t(value_expr_t::CONSTANT_I);
+ node->constant_i = std::atol(buf);
+ return node;
+ }
+ else if (c == '{') {
static char buf[2048];
- if (c == '{') {
+ in.get(c);
+ READ_INTO(in, buf, 2048, c, c != '}');
+ if (c == '}')
in.get(c);
- READ_INTO(in, buf, 2048, c, c != '}');
- if (c == '}')
- in.get(c);
- else
- throw value_expr_error("Missing '}'");
- } else {
- READ_INTO(in, buf, 2048, c, std::isdigit(c) || c == '.');
- }
+ else
+ throw value_expr_error("Missing '}'");
node = new value_expr_t(value_expr_t::CONSTANT_A);
node->constant_a.parse(buf);
@@ -613,7 +634,7 @@ value_expr_t * parse_logic_expr(std::istream& in)
node = new value_expr_t(value_expr_t::O_LT);
if (peek_next_nonws(in) == '=') {
in.get(c);
- node->type = value_expr_t::O_LTE;
+ node->kind = value_expr_t::O_LTE;
}
node->left = prev;
node->right = parse_add_expr(in);
@@ -625,7 +646,7 @@ value_expr_t * parse_logic_expr(std::istream& in)
node = new value_expr_t(value_expr_t::O_GT);
if (peek_next_nonws(in) == '=') {
in.get(c);
- node->type = value_expr_t::O_GTE;
+ node->kind = value_expr_t::O_GTE;
}
node->left = prev;
node->right = parse_add_expr(in);
@@ -708,13 +729,16 @@ value_expr_t * parse_value_expr(std::istream& in)
void dump_value_expr(std::ostream& out, const value_expr_t * node)
{
- switch (node->type) {
- case value_expr_t::CONSTANT_A:
- out << "CONST[" << node->constant_a << "]";
+ switch (node->kind) {
+ case value_expr_t::CONSTANT_I:
+ out << "UINT[" << node->constant_i << "]";
break;
case value_expr_t::CONSTANT_T:
out << "DATE/TIME[" << node->constant_t << "]";
break;
+ case value_expr_t::CONSTANT_A:
+ out << "CONST[" << node->constant_a << "]";
+ break;
case value_expr_t::AMOUNT: out << "AMOUNT"; break;
case value_expr_t::COST: out << "COST"; break;
@@ -794,7 +818,7 @@ void dump_value_expr(std::ostream& out, const value_expr_t * node)
case value_expr_t::O_OR:
out << "(";
dump_value_expr(out, node->left);
- switch (node->type) {
+ switch (node->kind) {
case value_expr_t::O_AND: out << " & "; break;
case value_expr_t::O_OR: out << " | "; break;
default: assert(0); break;
@@ -810,7 +834,7 @@ void dump_value_expr(std::ostream& out, const value_expr_t * node)
case value_expr_t::O_GTE:
out << "(";
dump_value_expr(out, node->left);
- switch (node->type) {
+ switch (node->kind) {
case value_expr_t::O_EQ: out << "="; break;
case value_expr_t::O_LT: out << "<"; break;
case value_expr_t::O_LTE: out << "<="; break;
@@ -828,7 +852,7 @@ void dump_value_expr(std::ostream& out, const value_expr_t * node)
case value_expr_t::O_DIV:
out << "(";
dump_value_expr(out, node->left);
- switch (node->type) {
+ switch (node->kind) {
case value_expr_t::O_ADD: out << "+"; break;
case value_expr_t::O_SUB: out << "-"; break;
case value_expr_t::O_MUL: out << "*"; break;
diff --git a/valexpr.h b/valexpr.h
index 21a3637d..d135a6b3 100644
--- a/valexpr.h
+++ b/valexpr.h
@@ -2,6 +2,7 @@
#define _EXPR_H
#include "ledger.h"
+#include "value.h"
#include "error.h"
namespace ledger {
@@ -42,8 +43,9 @@ struct value_expr_t
{
enum kind_t {
// Constants
- CONSTANT_A,
+ CONSTANT_I,
CONSTANT_T,
+ CONSTANT_A,
// Item details
AMOUNT,
@@ -93,16 +95,19 @@ struct value_expr_t
LAST
};
- kind_t type;
+ kind_t kind;
value_expr_t * left;
value_expr_t * right;
- amount_t constant_a;
- std::time_t constant_t;
- mask_t * mask;
+ union {
+ std::time_t constant_t;
+ unsigned int constant_i;
+ };
+ amount_t constant_a;
+ mask_t * mask;
- value_expr_t(const kind_t _type)
- : type(_type), left(NULL), right(NULL), mask(NULL) {}
+ value_expr_t(const kind_t _kind)
+ : kind(_kind), left(NULL), right(NULL), mask(NULL) {}
~value_expr_t() {
if (mask) delete mask;
@@ -110,7 +115,14 @@ struct value_expr_t
if (right) delete right;
}
- void compute(balance_t& result, const details_t& details) const;
+ void compute(value_t& result, const details_t& details,
+ value_t::type_t type = value_t::ANY) const;
+
+ void compute(balance_t& result, const details_t& details) const {
+ value_t value;
+ compute(value, details, value_t::BALANCE);
+ result = value.operator balance_t();
+ }
};
value_expr_t * parse_value_expr(std::istream& in);
@@ -170,7 +182,7 @@ class item_predicate
bool operator()(const T * item) const {
if (predicate) {
- balance_t result;
+ value_t result;
predicate->compute(result, details_t(item));
return result;
} else {
diff --git a/value.h b/value.h
new file mode 100644
index 00000000..31158594
--- /dev/null
+++ b/value.h
@@ -0,0 +1,995 @@
+#ifndef _VALUE_H
+#define _VALUE_H
+
+#include "amount.h"
+#include "balance.h"
+
+namespace ledger {
+
+// The following type is a polymorphous value type used solely for
+// performance reasons. The alternative is to compute value
+// expressions (valexpr.cc) in terms of the largest data type,
+// balance_t. This was found to be prohibitively expensive, especially
+// when large logic chains were involved, since many temporary
+// allocations would occur for every operator. With value_t, and the
+// fact that logic chains only need boolean values to continue, no
+// memory allocations need to take place at all.
+
+class value_t
+{
+ bool constructed;
+
+ value_t(const value_t& copy);
+
+ public:
+ char data[sizeof(balance_t)];
+
+ enum type_t {
+ BOOLEAN,
+ INTEGER,
+ AMOUNT,
+ BALANCE,
+ ANY
+ } type;
+
+ value_t() : constructed(false) {
+ *this = 0U;
+ }
+
+ value_t(const bool value) : constructed(false) {
+ *((bool *) data) = value;
+ type = BOOLEAN;
+ }
+ value_t(const unsigned int value) : constructed(false) {
+ *((unsigned int *) data) = value;
+ type = INTEGER;
+ }
+ value_t(const amount_t& value) : constructed(true) {
+ new((amount_t *)data) amount_t(value);
+ type = AMOUNT;
+ }
+ value_t(const balance_t& value) : constructed(true) {
+ new((balance_t *)data) balance_t(value);
+ type = BALANCE;
+ }
+
+ ~value_t() {
+ destroy();
+ }
+
+ void destroy() {
+ if (constructed) {
+ switch (type) {
+ case AMOUNT:
+ ((amount_t *)data)->~amount_t();
+ break;
+ case BALANCE:
+ ((balance_t *)data)->~balance_t();
+ break;
+ default:
+ break;
+ }
+ constructed = false;
+ }
+ }
+
+ value_t& operator=(const bool value) {
+ destroy();
+ *((bool *) data) = value;
+ type = BOOLEAN;
+ return *this;
+ }
+ value_t& operator=(const unsigned int value) {
+ destroy();
+ *((unsigned int *) data) = value;
+ type = INTEGER;
+ return *this;
+ }
+ value_t& operator=(const amount_t& value) {
+ destroy();
+ new((amount_t *)data) amount_t(value);
+ type = AMOUNT;
+ return *this;
+ }
+ value_t& operator=(const balance_t& value) {
+ destroy();
+ new((balance_t *)data) balance_t(value);
+ type = BALANCE;
+ return *this;
+ }
+
+ value_t& operator+=(const value_t& value) {
+ switch (value.type) {
+ case BOOLEAN:
+ case INTEGER:
+ switch (type) {
+ case BOOLEAN:
+ cast(INTEGER);
+ case INTEGER:
+ *((unsigned int *) data) += *((unsigned int *) value.data);
+ break;
+
+ case AMOUNT:
+ *((amount_t *) data) += *((unsigned int *) value.data);
+ break;
+
+ case BALANCE:
+ *((balance_t *) data) += amount_t(*((unsigned int *) value.data));
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case AMOUNT:
+ switch (type) {
+ case BOOLEAN:
+ case INTEGER:
+ cast(AMOUNT);
+ case AMOUNT:
+ *((amount_t *) data) += *((amount_t *) value.data);
+ break;
+
+ case BALANCE:
+ *((balance_t *) data) += *((amount_t *) value.data);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case BALANCE:
+ switch (type) {
+ case BOOLEAN:
+ case INTEGER:
+ case AMOUNT:
+ cast(BALANCE);
+ case BALANCE:
+ *((balance_t *) data) += *((balance_t *) value.data);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ return *this;
+ }
+
+ value_t& operator-=(const value_t& value) {
+ switch (value.type) {
+ case BOOLEAN:
+ case INTEGER:
+ switch (type) {
+ case BOOLEAN:
+ cast(INTEGER);
+ case INTEGER:
+ *((unsigned int *) data) -= *((unsigned int *) value.data);
+ break;
+
+ case AMOUNT:
+ *((amount_t *) data) -= *((unsigned int *) value.data);
+ break;
+
+ case BALANCE:
+ *((balance_t *) data) -= amount_t(*((unsigned int *) value.data));
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case AMOUNT:
+ switch (type) {
+ case BOOLEAN:
+ case INTEGER:
+ cast(AMOUNT);
+ case AMOUNT:
+ *((amount_t *) data) -= *((amount_t *) value.data);
+ break;
+
+ case BALANCE:
+ *((balance_t *) data) -= *((amount_t *) value.data);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case BALANCE:
+ switch (type) {
+ case BOOLEAN:
+ case INTEGER:
+ case AMOUNT:
+ cast(BALANCE);
+ case BALANCE:
+ *((balance_t *) data) -= *((balance_t *) value.data);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ return *this;
+ }
+
+ value_t& operator*=(const value_t& value) {
+ switch (value.type) {
+ case BOOLEAN:
+ case INTEGER:
+ switch (type) {
+ case BOOLEAN:
+ cast(INTEGER);
+ case INTEGER:
+ *((unsigned int *) data) *= *((unsigned int *) value.data);
+ break;
+
+ case AMOUNT:
+ *((amount_t *) data) *= *((unsigned int *) value.data);
+ break;
+
+ case BALANCE:
+ *((balance_t *) data) *= amount_t(*((unsigned int *) value.data));
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case AMOUNT:
+ switch (type) {
+ case BOOLEAN:
+ case INTEGER:
+ cast(AMOUNT);
+ case AMOUNT:
+ *((amount_t *) data) *= *((amount_t *) value.data);
+ break;
+
+ case BALANCE:
+ *((balance_t *) data) *= *((amount_t *) value.data);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case BALANCE:
+ switch (type) {
+ case BOOLEAN:
+ case INTEGER:
+ case AMOUNT:
+ cast(BALANCE);
+ case BALANCE:
+ *((balance_t *) data) *= *((balance_t *) value.data);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ return *this;
+ }
+
+ value_t& operator/=(const value_t& value) {
+ switch (value.type) {
+ case BOOLEAN:
+ case INTEGER:
+ switch (type) {
+ case BOOLEAN:
+ cast(INTEGER);
+ case INTEGER:
+ *((unsigned int *) data) /= *((unsigned int *) value.data);
+ break;
+
+ case AMOUNT:
+ *((amount_t *) data) /= *((unsigned int *) value.data);
+ break;
+
+ case BALANCE:
+ *((balance_t *) data) /= amount_t(*((unsigned int *) value.data));
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case AMOUNT:
+ switch (type) {
+ case BOOLEAN:
+ case INTEGER:
+ cast(AMOUNT);
+ case AMOUNT:
+ *((amount_t *) data) /= *((amount_t *) value.data);
+ break;
+
+ case BALANCE:
+ *((balance_t *) data) /= *((amount_t *) value.data);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case BALANCE:
+ switch (type) {
+ case BOOLEAN:
+ case INTEGER:
+ case AMOUNT:
+ cast(BALANCE);
+ case BALANCE:
+ *((balance_t *) data) /= *((balance_t *) value.data);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ return *this;
+ }
+
+ bool operator==(const value_t& value) {
+ switch (value.type) {
+ case BOOLEAN:
+ switch (type) {
+ case BOOLEAN:
+ return *((bool *) data) == *((bool *) value.data);
+
+ case INTEGER:
+ return bool(*((unsigned int *) data)) == *((bool *) value.data);
+
+ case AMOUNT:
+ return bool(*((amount_t *) data)) == *((bool *) value.data);
+
+ case BALANCE:
+ return bool(*((balance_t *) data)) == *((bool *) value.data);
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case INTEGER:
+ switch (type) {
+ case BOOLEAN:
+ return ((unsigned int) *((bool *) data)) == *((unsigned int *) value.data);
+
+ case INTEGER:
+ return *((unsigned int *) data) == *((unsigned int *) value.data);
+
+ case AMOUNT:
+ return ((unsigned int) *((amount_t *) data)) == *((unsigned int *) value.data);
+
+ case BALANCE:
+ return ((unsigned int) *((balance_t *) data)) == *((unsigned int *) value.data);
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case AMOUNT:
+ switch (type) {
+ case BOOLEAN:
+ return amount_t(*((bool *) data)) == *((amount_t *) value.data);
+
+ case INTEGER:
+ return amount_t(*((unsigned int *) data)) == *((amount_t *) value.data);
+
+ case AMOUNT:
+ return *((amount_t *) data) == *((amount_t *) value.data);
+
+ case BALANCE:
+ return ((balance_t *) data)->amount() == *((amount_t *) value.data);
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case BALANCE:
+ switch (type) {
+ case BOOLEAN:
+ return balance_t(*((bool *) data)) == *((balance_t *) value.data);
+
+ case INTEGER:
+ return balance_t(*((unsigned int *) data)) == *((balance_t *) value.data);
+
+ case AMOUNT:
+ return balance_t(*((amount_t *) data)) == *((balance_t *) value.data);
+
+ case BALANCE:
+ return *((balance_t *) data) == *((balance_t *) value.data);
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ return *this;
+ }
+ bool operator!=(const value_t& value) {
+ return ! (*this == value);
+ }
+
+ bool operator<(const value_t& value) {
+ switch (value.type) {
+ case BOOLEAN:
+ switch (type) {
+ case BOOLEAN:
+ return *((bool *) data) < *((bool *) value.data);
+
+ case INTEGER:
+ return bool(*((unsigned int *) data)) < *((bool *) value.data);
+
+ case AMOUNT:
+ return bool(*((amount_t *) data)) < *((bool *) value.data);
+
+ case BALANCE:
+ return bool(*((balance_t *) data)) < *((bool *) value.data);
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case INTEGER:
+ switch (type) {
+ case BOOLEAN:
+ return ((unsigned int) *((bool *) data)) < *((unsigned int *) value.data);
+
+ case INTEGER:
+ return *((unsigned int *) data) < *((unsigned int *) value.data);
+
+ case AMOUNT:
+ return *((amount_t *) data) < *((unsigned int *) value.data);
+
+ case BALANCE:
+ return *((balance_t *) data) < *((unsigned int *) value.data);
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case AMOUNT:
+ switch (type) {
+ case BOOLEAN:
+ return amount_t(*((bool *) data)) < *((amount_t *) value.data);
+
+ case INTEGER:
+ return amount_t(*((unsigned int *) data)) < *((amount_t *) value.data);
+
+ case AMOUNT:
+ return *((amount_t *) data) < *((amount_t *) value.data);
+
+ case BALANCE:
+ return ((balance_t *) data)->amount(((amount_t *) value.data)->commodity) < *((amount_t *) value.data);
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case BALANCE:
+ switch (type) {
+ case BOOLEAN:
+ return balance_t(*((bool *) data)) < *((balance_t *) value.data);
+
+ case INTEGER:
+ return balance_t(*((unsigned int *) data)) < *((balance_t *) value.data);
+
+ case AMOUNT:
+ return balance_t(*((amount_t *) data)) < *((balance_t *) value.data);
+
+ case BALANCE:
+ return *((balance_t *) data) < *((balance_t *) value.data);
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ return *this;
+ }
+
+ bool operator<=(const value_t& value) {
+ switch (value.type) {
+ case BOOLEAN:
+ switch (type) {
+ case BOOLEAN:
+ return *((bool *) data) <= *((bool *) value.data);
+
+ case INTEGER:
+ return bool(*((unsigned int *) data)) <= *((bool *) value.data);
+
+ case AMOUNT:
+ return bool(*((amount_t *) data)) <= *((bool *) value.data);
+
+ case BALANCE:
+ return bool(*((balance_t *) data)) <= *((bool *) value.data);
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case INTEGER:
+ switch (type) {
+ case BOOLEAN:
+ return ((unsigned int) *((bool *) data)) <= *((unsigned int *) value.data);
+
+ case INTEGER:
+ return *((unsigned int *) data) <= *((unsigned int *) value.data);
+
+ case AMOUNT:
+ return ((unsigned int) *((amount_t *) data)) <= *((unsigned int *) value.data);
+
+ case BALANCE:
+ return ((unsigned int) *((balance_t *) data)) <= *((unsigned int *) value.data);
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case AMOUNT:
+ switch (type) {
+ case BOOLEAN:
+ return amount_t(*((bool *) data)) <= *((amount_t *) value.data);
+
+ case INTEGER:
+ return amount_t(*((unsigned int *) data)) <= *((amount_t *) value.data);
+
+ case AMOUNT:
+ return *((amount_t *) data) <= *((amount_t *) value.data);
+
+ case BALANCE:
+ return ((balance_t *) data)->amount() <= *((amount_t *) value.data);
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case BALANCE:
+ switch (type) {
+ case BOOLEAN:
+ return balance_t(*((bool *) data)) <= *((balance_t *) value.data);
+
+ case INTEGER:
+ return balance_t(*((unsigned int *) data)) <= *((balance_t *) value.data);
+
+ case AMOUNT:
+ return balance_t(*((amount_t *) data)) <= *((balance_t *) value.data);
+
+ case BALANCE:
+ return *((balance_t *) data) <= *((balance_t *) value.data);
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ return *this;
+ }
+
+ bool operator>(const value_t& value) {
+ switch (value.type) {
+ case BOOLEAN:
+ switch (type) {
+ case BOOLEAN:
+ return *((bool *) data) > *((bool *) value.data);
+
+ case INTEGER:
+ return bool(*((unsigned int *) data)) > *((bool *) value.data);
+
+ case AMOUNT:
+ return bool(*((amount_t *) data)) > *((bool *) value.data);
+
+ case BALANCE:
+ return bool(*((balance_t *) data)) > *((bool *) value.data);
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case INTEGER:
+ switch (type) {
+ case BOOLEAN:
+ return ((unsigned int) *((bool *) data)) > *((unsigned int *) value.data);
+
+ case INTEGER:
+ return *((unsigned int *) data) > *((unsigned int *) value.data);
+
+ case AMOUNT:
+ return ((unsigned int) *((amount_t *) data)) > *((unsigned int *) value.data);
+
+ case BALANCE:
+ return ((unsigned int) *((balance_t *) data)) > *((unsigned int *) value.data);
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case AMOUNT:
+ switch (type) {
+ case BOOLEAN:
+ return amount_t(*((bool *) data)) > *((amount_t *) value.data);
+
+ case INTEGER:
+ return amount_t(*((unsigned int *) data)) > *((amount_t *) value.data);
+
+ case AMOUNT:
+ return *((amount_t *) data) > *((amount_t *) value.data);
+
+ case BALANCE:
+ return ((balance_t *) data)->amount(((amount_t *) value.data)->commodity) > *((amount_t *) value.data);
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case BALANCE:
+ switch (type) {
+ case BOOLEAN:
+ return balance_t(*((bool *) data)) > *((balance_t *) value.data);
+
+ case INTEGER:
+ return balance_t(*((unsigned int *) data)) > *((balance_t *) value.data);
+
+ case AMOUNT:
+ return balance_t(*((amount_t *) data)) > *((balance_t *) value.data);
+
+ case BALANCE:
+ return *((balance_t *) data) > *((balance_t *) value.data);
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ return *this;
+ }
+
+ bool operator>=(const value_t& value) {
+ switch (value.type) {
+ case BOOLEAN:
+ switch (type) {
+ case BOOLEAN:
+ return *((bool *) data) >= *((bool *) value.data);
+
+ case INTEGER:
+ return bool(*((unsigned int *) data)) >= *((bool *) value.data);
+
+ case AMOUNT:
+ return bool(*((amount_t *) data)) >= *((bool *) value.data);
+
+ case BALANCE:
+ return bool(*((balance_t *) data)) >= *((bool *) value.data);
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case INTEGER:
+ switch (type) {
+ case BOOLEAN:
+ return ((unsigned int) *((bool *) data)) >= *((unsigned int *) value.data);
+
+ case INTEGER:
+ return *((unsigned int *) data) >= *((unsigned int *) value.data);
+
+ case AMOUNT:
+ return ((unsigned int) *((amount_t *) data)) >= *((unsigned int *) value.data);
+
+ case BALANCE:
+ return ((unsigned int) *((balance_t *) data)) >= *((unsigned int *) value.data);
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case AMOUNT:
+ switch (type) {
+ case BOOLEAN:
+ return amount_t(*((bool *) data)) >= *((amount_t *) value.data);
+
+ case INTEGER:
+ return amount_t(*((unsigned int *) data)) >= *((amount_t *) value.data);
+
+ case AMOUNT:
+ return *((amount_t *) data) >= *((amount_t *) value.data);
+
+ case BALANCE:
+ return ((balance_t *) data)->amount() >= *((amount_t *) value.data);
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case BALANCE:
+ switch (type) {
+ case BOOLEAN:
+ return balance_t(*((bool *) data)) >= *((balance_t *) value.data);
+
+ case INTEGER:
+ return balance_t(*((unsigned int *) data)) >= *((balance_t *) value.data);
+
+ case AMOUNT:
+ return balance_t(*((amount_t *) data)) >= *((balance_t *) value.data);
+
+ case BALANCE:
+ return *((balance_t *) data) >= *((balance_t *) value.data);
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ return *this;
+ }
+
+ template <typename T>
+ operator T() const {
+ switch (type) {
+ case BOOLEAN:
+ return *((bool *) data);
+ case INTEGER:
+ return *((unsigned int *) data);
+ case AMOUNT:
+ return *((amount_t *) data);
+ case BALANCE:
+ return *((balance_t *) data);
+
+ default:
+ assert(0);
+ break;
+ }
+ assert(0);
+ return 0;
+ }
+
+ void cast(type_t cast_type) {
+ switch (type) {
+ case BOOLEAN:
+ switch (cast_type) {
+ case BOOLEAN:
+ break;
+ case INTEGER:
+ *((unsigned int *) data) = *((bool *) data);
+ break;
+ case AMOUNT:
+ new((amount_t *)data) amount_t(*((bool *) data));
+ constructed = true;
+ break;
+ case BALANCE:
+ new((balance_t *)data) balance_t(*((bool *) data));
+ constructed = true;
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case INTEGER:
+ switch (cast_type) {
+ case BOOLEAN:
+ *((bool *) data) = *((unsigned int *) data);
+ break;
+ case INTEGER:
+ break;
+ case AMOUNT:
+ new((amount_t *)data) amount_t(*((unsigned int *) data));
+ constructed = true;
+ break;
+ case BALANCE:
+ new((balance_t *)data) balance_t(*((unsigned int *) data));
+ constructed = true;
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case AMOUNT:
+ switch (cast_type) {
+ case BOOLEAN: {
+ bool temp = *((amount_t *) data);
+ destroy();
+ *((bool *)data) = temp;
+ break;
+ }
+ case INTEGER: {
+ unsigned int temp = *((amount_t *) data);
+ destroy();
+ *((unsigned int *)data) = temp;
+ break;
+ }
+ case AMOUNT:
+ break;
+ case BALANCE: {
+ amount_t temp = *((amount_t *) data);
+ destroy();
+ new((balance_t *)data) balance_t(temp);
+ constructed = true;
+ break;
+ }
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case BALANCE:
+ switch (cast_type) {
+ case BOOLEAN: {
+ bool temp = *((balance_t *) data);
+ destroy();
+ *((bool *)data) = temp;
+ break;
+ }
+ case INTEGER: {
+ unsigned int temp = ((balance_t *) data)->amount();
+ destroy();
+ *((unsigned int *)data) = temp;
+ break;
+ }
+ case AMOUNT: {
+ amount_t temp = ((balance_t *) data)->amount();
+ destroy();
+ new((amount_t *)data) amount_t(temp);
+ constructed = true;
+ break;
+ }
+ case BALANCE:
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ type = cast_type;
+ }
+
+ void negate() {
+ switch (type) {
+ case BOOLEAN:
+ *((bool *) data) = ! *((bool *) data);
+ break;
+ case INTEGER:
+ *((unsigned int *) data) = - *((unsigned int *) data);
+ break;
+ case AMOUNT:
+ ((amount_t *) data)->negate();
+ break;
+ case BALANCE:
+ ((balance_t *) data)->negate();
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ }
+
+ void abs() {
+ switch (type) {
+ case BOOLEAN:
+ break;
+ case INTEGER:
+ if (*((unsigned int *) data) < 0)
+ *((unsigned int *) data) = - *((unsigned int *) data);
+ break;
+ case AMOUNT:
+ ((amount_t *) data)->abs();
+ break;
+ case BALANCE:
+ ((balance_t *) data)->abs();
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ }
+};
+
+} // namespace ledger
+
+#endif // _VALUE_H