summaryrefslogtreecommitdiff
path: root/value.h
diff options
context:
space:
mode:
Diffstat (limited to 'value.h')
-rw-r--r--value.h995
1 files changed, 995 insertions, 0 deletions
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