summaryrefslogtreecommitdiff
path: root/src/value.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/value.cc')
-rw-r--r--src/value.cc2311
1 files changed, 2311 insertions, 0 deletions
diff --git a/src/value.cc b/src/value.cc
new file mode 100644
index 00000000..914a49e2
--- /dev/null
+++ b/src/value.cc
@@ -0,0 +1,2311 @@
+#include "value.h"
+#include "xml.h"
+
+namespace ledger {
+
+bool value_t::to_boolean() const
+{
+ if (type == BOOLEAN) {
+ return *(bool *) data;
+ } else {
+ value_t temp(*this);
+ temp.in_place_cast(BOOLEAN);
+ return *(bool *) temp.data;
+ }
+}
+
+long value_t::to_integer() const
+{
+ if (type == INTEGER) {
+ return *(long *) data;
+ } else {
+ value_t temp(*this);
+ temp.in_place_cast(INTEGER);
+ return *(long *) temp.data;
+ }
+}
+
+moment_t value_t::to_datetime() const
+{
+ if (type == DATETIME) {
+ return *(moment_t *) data;
+ } else {
+ value_t temp(*this);
+ temp.in_place_cast(DATETIME);
+ return *(moment_t *) temp.data;
+ }
+}
+
+amount_t value_t::to_amount() const
+{
+ if (type == AMOUNT) {
+ return *(amount_t *) data;
+ } else {
+ value_t temp(*this);
+ temp.in_place_cast(AMOUNT);
+ return *(amount_t *) temp.data;
+ }
+}
+
+balance_t value_t::to_balance() const
+{
+ if (type == BALANCE) {
+ return *(balance_t *) data;
+ } else {
+ value_t temp(*this);
+ temp.in_place_cast(BALANCE);
+ return *(balance_t *) temp.data;
+ }
+}
+
+balance_pair_t value_t::to_balance_pair() const
+{
+ if (type == BALANCE_PAIR) {
+ return *(balance_pair_t *) data;
+ } else {
+ value_t temp(*this);
+ temp.in_place_cast(BALANCE_PAIR);
+ return *(balance_pair_t *) temp.data;
+ }
+}
+
+string value_t::to_string() const
+{
+ if (type == STRING) {
+ return **(string **) data;
+ } else {
+ std::ostringstream out;
+ out << *this;
+ return out.str();
+ }
+}
+
+xml::node_t * value_t::to_xml_node() const
+{
+ if (type == XML_NODE)
+ return *(xml::node_t **) data;
+ else
+ throw_(value_exception, "Value is not an XML node");
+}
+
+void * value_t::to_pointer() const
+{
+ if (type == POINTER)
+ return *(void **) data;
+ else
+ throw_(value_exception, "Value is not a pointer");
+}
+
+value_t::sequence_t * value_t::to_sequence() const
+{
+ if (type == SEQUENCE)
+ return *(sequence_t **) data;
+ else
+ throw_(value_exception, "Value is not a sequence");
+}
+
+void value_t::destroy()
+{
+ switch (type) {
+ case AMOUNT:
+ ((amount_t *)data)->~amount_t();
+ break;
+ case BALANCE:
+ ((balance_t *)data)->~balance_t();
+ break;
+ case BALANCE_PAIR:
+ ((balance_pair_t *)data)->~balance_pair_t();
+ break;
+ case STRING:
+ delete *(string **) data;
+ break;
+ case SEQUENCE:
+ delete *(sequence_t **) data;
+ break;
+ default:
+ break;
+ }
+}
+
+void value_t::simplify()
+{
+ if (realzero()) {
+ DEBUG_("amounts.values.simplify", "Zeroing type " << type);
+ *this = 0L;
+ return;
+ }
+
+ if (type == BALANCE_PAIR &&
+ (! ((balance_pair_t *) data)->cost ||
+ ((balance_pair_t *) data)->cost->realzero())) {
+ DEBUG_("amounts.values.simplify", "Reducing balance pair to balance");
+ in_place_cast(BALANCE);
+ }
+
+ if (type == BALANCE &&
+ ((balance_t *) data)->amounts.size() == 1) {
+ DEBUG_("amounts.values.simplify", "Reducing balance to amount");
+ in_place_cast(AMOUNT);
+ }
+
+ if (type == AMOUNT &&
+ ! ((amount_t *) data)->commodity()) {
+ DEBUG_("amounts.values.simplify", "Reducing amount to integer");
+ in_place_cast(INTEGER);
+ }
+}
+
+value_t& value_t::operator=(const value_t& val)
+{
+ if (this == &val)
+ return *this;
+
+ if (type == BOOLEAN && val.type == BOOLEAN) {
+ *((bool *) data) = *((bool *) val.data);
+ return *this;
+ }
+ else if (type == INTEGER && val.type == INTEGER) {
+ *((long *) data) = *((long *) val.data);
+ return *this;
+ }
+ else if (type == DATETIME && val.type == DATETIME) {
+ *((moment_t *) data) = *((moment_t *) val.data);
+ return *this;
+ }
+ else if (type == AMOUNT && val.type == AMOUNT) {
+ *(amount_t *) data = *(amount_t *) val.data;
+ return *this;
+ }
+ else if (type == BALANCE && val.type == BALANCE) {
+ *(balance_t *) data = *(balance_t *) val.data;
+ return *this;
+ }
+ else if (type == BALANCE_PAIR && val.type == BALANCE_PAIR) {
+ *(balance_pair_t *) data = *(balance_pair_t *) val.data;
+ return *this;
+ }
+ else if (type == STRING && val.type == STRING) {
+ **(string **) data = **(string **) val.data;
+ return *this;
+ }
+ else if (type == SEQUENCE && val.type == SEQUENCE) {
+ **(sequence_t **) data = **(sequence_t **) val.data;
+ return *this;
+ }
+
+ destroy();
+
+ switch (val.type) {
+ case BOOLEAN:
+ *((bool *) data) = *((bool *) val.data);
+ break;
+
+ case INTEGER:
+ *((long *) data) = *((long *) val.data);
+ break;
+
+ case DATETIME:
+ *((moment_t *) data) = *((moment_t *) val.data);
+ break;
+
+ case AMOUNT:
+ new((amount_t *)data) amount_t(*((amount_t *) val.data));
+ break;
+
+ case BALANCE:
+ new((balance_t *)data) balance_t(*((balance_t *) val.data));
+ break;
+
+ case BALANCE_PAIR:
+ new((balance_pair_t *)data) balance_pair_t(*((balance_pair_t *) val.data));
+ break;
+
+ case STRING:
+ *(string **) data = new string(**(string **) val.data);
+ break;
+
+ case XML_NODE:
+ *(xml::node_t **) data = *(xml::node_t **) val.data;
+ break;
+
+ case POINTER:
+ *(void **) data = *(void **) val.data;
+ break;
+
+ case SEQUENCE:
+ *(sequence_t **) data = new sequence_t(**(sequence_t **) val.data);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+
+ type = val.type;
+
+ return *this;
+}
+
+value_t& value_t::operator+=(const value_t& val)
+{
+ if (val.type == BOOLEAN)
+ throw_(value_exception, "Cannot add a boolean to a value");
+ else if (val.type == DATETIME)
+ throw_(value_exception, "Cannot add a date/time to a value");
+ else if (val.type == POINTER)
+ throw_(value_exception, "Cannot add a pointer to a value");
+ else if (val.type == SEQUENCE)
+ throw_(value_exception, "Cannot add a sequence to a value");
+ else if (val.type == XML_NODE) // recurse
+ return *this += (*(xml::node_t **) val.data)->to_value();
+
+ switch (type) {
+ case BOOLEAN:
+ throw_(value_exception, "Cannot add a value to a boolean");
+
+ case INTEGER:
+ switch (val.type) {
+ case INTEGER:
+ *((long *) data) += *((long *) val.data);
+ break;
+ case AMOUNT:
+ in_place_cast(AMOUNT);
+ *((amount_t *) data) += *((amount_t *) val.data);
+ break;
+ case BALANCE:
+ in_place_cast(BALANCE);
+ *((balance_t *) data) += *((balance_t *) val.data);
+ break;
+ case BALANCE_PAIR:
+ in_place_cast(BALANCE_PAIR);
+ *((balance_pair_t *) data) += *((balance_pair_t *) val.data);
+ break;
+ case STRING:
+ throw_(value_exception, "Cannot add a string to an integer");
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case DATETIME:
+ switch (val.type) {
+ case INTEGER:
+ *((moment_t *) data) += date_duration(*((long *) val.data));
+ break;
+ case AMOUNT:
+ *((moment_t *) data) += date_duration(long(*((amount_t *) val.data)));
+ break;
+ case BALANCE:
+ *((moment_t *) data) += date_duration(long(*((balance_t *) val.data)));
+ break;
+ case BALANCE_PAIR:
+ *((moment_t *) data) += date_duration(long(*((balance_pair_t *) val.data)));
+ break;
+ case STRING:
+ throw_(value_exception, "Cannot add a string to an date/time");
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case AMOUNT:
+ switch (val.type) {
+ case INTEGER:
+ if (*((long *) val.data) &&
+ ((amount_t *) data)->commodity()) {
+ in_place_cast(BALANCE);
+ return *this += val;
+ }
+ *((amount_t *) data) += *((long *) val.data);
+ break;
+
+ case AMOUNT:
+ if (((amount_t *) data)->commodity() !=
+ ((amount_t *) val.data)->commodity()) {
+ in_place_cast(BALANCE);
+ return *this += val;
+ }
+ *((amount_t *) data) += *((amount_t *) val.data);
+ break;
+
+ case BALANCE:
+ in_place_cast(BALANCE);
+ *((balance_t *) data) += *((balance_t *) val.data);
+ break;
+
+ case BALANCE_PAIR:
+ in_place_cast(BALANCE_PAIR);
+ *((balance_pair_t *) data) += *((balance_pair_t *) val.data);
+ break;
+
+ case STRING:
+ throw_(value_exception, "Cannot add a string to an amount");
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case BALANCE:
+ switch (val.type) {
+ case INTEGER:
+ *((balance_t *) data) += *((long *) val.data);
+ break;
+ case AMOUNT:
+ *((balance_t *) data) += *((amount_t *) val.data);
+ break;
+ case BALANCE:
+ *((balance_t *) data) += *((balance_t *) val.data);
+ break;
+ case BALANCE_PAIR:
+ in_place_cast(BALANCE_PAIR);
+ *((balance_pair_t *) data) += *((balance_pair_t *) val.data);
+ break;
+ case STRING:
+ throw_(value_exception, "Cannot add a string to an balance");
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case BALANCE_PAIR:
+ switch (val.type) {
+ case INTEGER:
+ *((balance_pair_t *) data) += *((long *) val.data);
+ break;
+ case AMOUNT:
+ *((balance_pair_t *) data) += *((amount_t *) val.data);
+ break;
+ case BALANCE:
+ *((balance_pair_t *) data) += *((balance_t *) val.data);
+ break;
+ case BALANCE_PAIR:
+ *((balance_pair_t *) data) += *((balance_pair_t *) val.data);
+ break;
+ case STRING:
+ throw_(value_exception, "Cannot add a string to an balance pair");
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case STRING:
+ switch (val.type) {
+ case INTEGER:
+ throw_(value_exception, "Cannot add an integer to a string");
+ case AMOUNT:
+ throw_(value_exception, "Cannot add an amount to a string");
+ case BALANCE:
+ throw_(value_exception, "Cannot add a balance to a string");
+ case BALANCE_PAIR:
+ throw_(value_exception, "Cannot add a balance pair to a string");
+ case STRING:
+ **(string **) data += **(string **) val.data;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case XML_NODE:
+ throw_(value_exception, "Cannot add a value to an XML node");
+
+ case POINTER:
+ throw_(value_exception, "Cannot add a value to a pointer");
+
+ case SEQUENCE:
+ throw_(value_exception, "Cannot add a value to a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ return *this;
+}
+
+value_t& value_t::operator-=(const value_t& val)
+{
+ if (val.type == BOOLEAN)
+ throw_(value_exception, "Cannot subtract a boolean from a value");
+ else if (val.type == DATETIME && type != DATETIME)
+ throw_(value_exception, "Cannot subtract a date/time from a value");
+ else if (val.type == STRING)
+ throw_(value_exception, "Cannot subtract a string from a value");
+ else if (val.type == POINTER)
+ throw_(value_exception, "Cannot subtract a pointer from a value");
+ else if (val.type == SEQUENCE)
+ throw_(value_exception, "Cannot subtract a sequence from a value");
+ else if (val.type == XML_NODE) // recurse
+ return *this -= (*(xml::node_t **) val.data)->to_value();
+
+ switch (type) {
+ case BOOLEAN:
+ throw_(value_exception, "Cannot subtract a value from a boolean");
+
+ case INTEGER:
+ switch (val.type) {
+ case INTEGER:
+ *((long *) data) -= *((long *) val.data);
+ break;
+ case AMOUNT:
+ in_place_cast(AMOUNT);
+ *((amount_t *) data) -= *((amount_t *) val.data);
+ break;
+ case BALANCE:
+ in_place_cast(BALANCE);
+ *((balance_t *) data) -= *((balance_t *) val.data);
+ break;
+ case BALANCE_PAIR:
+ in_place_cast(BALANCE_PAIR);
+ *((balance_pair_t *) data) -= *((balance_pair_t *) val.data);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case DATETIME:
+ switch (val.type) {
+ case INTEGER:
+ *((moment_t *) data) -= date_duration(*((long *) val.data));
+ break;
+ case DATETIME: {
+ duration_t tval = ((moment_t *) data)->operator-(*((moment_t *) val.data));
+ in_place_cast(INTEGER);
+ *((long *) data) = tval.total_seconds() / 86400L;
+ break;
+ }
+ case AMOUNT:
+ *((moment_t *) data) -= date_duration(long(*((amount_t *) val.data)));
+ break;
+ case BALANCE:
+ *((moment_t *) data) -= date_duration(long(*((balance_t *) val.data)));
+ break;
+ case BALANCE_PAIR:
+ *((moment_t *) data) -= date_duration(long(*((balance_pair_t *) val.data)));
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case AMOUNT:
+ switch (val.type) {
+ case INTEGER:
+ if (*((long *) val.data) &&
+ ((amount_t *) data)->commodity()) {
+ in_place_cast(BALANCE);
+ return *this -= val;
+ }
+ *((amount_t *) data) -= *((long *) val.data);
+ break;
+
+ case AMOUNT:
+ if (((amount_t *) data)->commodity() !=
+ ((amount_t *) val.data)->commodity()) {
+ in_place_cast(BALANCE);
+ return *this -= val;
+ }
+ *((amount_t *) data) -= *((amount_t *) val.data);
+ break;
+
+ case BALANCE:
+ in_place_cast(BALANCE);
+ *((balance_t *) data) -= *((balance_t *) val.data);
+ break;
+
+ case BALANCE_PAIR:
+ in_place_cast(BALANCE_PAIR);
+ *((balance_pair_t *) data) -= *((balance_pair_t *) val.data);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case BALANCE:
+ switch (val.type) {
+ case INTEGER:
+ *((balance_t *) data) -= *((long *) val.data);
+ break;
+ case AMOUNT:
+ *((balance_t *) data) -= *((amount_t *) val.data);
+ break;
+ case BALANCE:
+ *((balance_t *) data) -= *((balance_t *) val.data);
+ break;
+ case BALANCE_PAIR:
+ in_place_cast(BALANCE_PAIR);
+ *((balance_pair_t *) data) -= *((balance_pair_t *) val.data);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case BALANCE_PAIR:
+ switch (val.type) {
+ case INTEGER:
+ *((balance_pair_t *) data) -= *((long *) val.data);
+ break;
+ case AMOUNT:
+ *((balance_pair_t *) data) -= *((amount_t *) val.data);
+ break;
+ case BALANCE:
+ *((balance_pair_t *) data) -= *((balance_t *) val.data);
+ break;
+ case BALANCE_PAIR:
+ *((balance_pair_t *) data) -= *((balance_pair_t *) val.data);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case STRING:
+ throw_(value_exception, "Cannot subtract a value from a string");
+ case XML_NODE:
+ throw_(value_exception, "Cannot subtract a value from an XML node");
+ case POINTER:
+ throw_(value_exception, "Cannot subtract a value from a pointer");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot subtract a value from a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+
+ simplify();
+
+ return *this;
+}
+
+value_t& value_t::operator*=(const value_t& val)
+{
+ if (val.type == BOOLEAN)
+ throw_(value_exception, "Cannot multiply a value by a boolean");
+ else if (val.type == DATETIME)
+ throw_(value_exception, "Cannot multiply a value by a date/time");
+ else if (val.type == STRING)
+ throw_(value_exception, "Cannot multiply a value by a string");
+ else if (val.type == POINTER)
+ throw_(value_exception, "Cannot multiply a value by a pointer");
+ else if (val.type == SEQUENCE)
+ throw_(value_exception, "Cannot multiply a value by a sequence");
+ else if (val.type == XML_NODE) // recurse
+ return *this *= (*(xml::node_t **) val.data)->to_value();
+
+ if (val.realzero() && type != STRING) {
+ *this = 0L;
+ return *this;
+ }
+
+ switch (type) {
+ case BOOLEAN:
+ throw_(value_exception, "Cannot multiply a value by a boolean");
+
+ case INTEGER:
+ switch (val.type) {
+ case INTEGER:
+ *((long *) data) *= *((long *) val.data);
+ break;
+ case AMOUNT:
+ in_place_cast(AMOUNT);
+ *((amount_t *) data) *= *((amount_t *) val.data);
+ break;
+ case BALANCE:
+ in_place_cast(BALANCE);
+ *((balance_t *) data) *= *((balance_t *) val.data);
+ break;
+ case BALANCE_PAIR:
+ in_place_cast(BALANCE_PAIR);
+ *((balance_pair_t *) data) *= *((balance_pair_t *) val.data);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case AMOUNT:
+ switch (val.type) {
+ case INTEGER:
+ *((amount_t *) data) *= *((long *) val.data);
+ break;
+ case AMOUNT:
+ *((amount_t *) data) *= *((amount_t *) val.data);
+ break;
+ case BALANCE:
+ in_place_cast(BALANCE);
+ *((balance_t *) data) *= *((balance_t *) val.data);
+ break;
+ case BALANCE_PAIR:
+ in_place_cast(BALANCE_PAIR);
+ *((balance_pair_t *) data) *= *((balance_pair_t *) val.data);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case BALANCE:
+ switch (val.type) {
+ case INTEGER:
+ *((balance_t *) data) *= *((long *) val.data);
+ break;
+ case AMOUNT:
+ *((balance_t *) data) *= *((amount_t *) val.data);
+ break;
+ case BALANCE:
+ *((balance_t *) data) *= *((balance_t *) val.data);
+ break;
+ case BALANCE_PAIR:
+ in_place_cast(BALANCE_PAIR);
+ *((balance_pair_t *) data) *= *((balance_pair_t *) val.data);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case BALANCE_PAIR:
+ switch (val.type) {
+ case INTEGER:
+ *((balance_pair_t *) data) *= *((long *) val.data);
+ break;
+ case AMOUNT:
+ *((balance_pair_t *) data) *= *((amount_t *) val.data);
+ break;
+ case BALANCE:
+ *((balance_pair_t *) data) *= *((balance_t *) val.data);
+ break;
+ case BALANCE_PAIR:
+ *((balance_pair_t *) data) *= *((balance_pair_t *) val.data);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case STRING:
+ switch (val.type) {
+ case INTEGER: {
+ string temp;
+ for (long i = 0; i < *(long *) val.data; i++)
+ temp += **(string **) data;
+ **(string **) data = temp;
+ break;
+ }
+ case AMOUNT: {
+ string temp;
+ value_t num(val);
+ num.in_place_cast(INTEGER);
+ for (long i = 0; i < *(long *) num.data; i++)
+ temp += **(string **) data;
+ **(string **) data = temp;
+ break;
+ }
+ case BALANCE:
+ throw_(value_exception, "Cannot multiply a string by a balance");
+ case BALANCE_PAIR:
+ throw_(value_exception, "Cannot multiply a string by a balance pair");
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case XML_NODE:
+ throw_(value_exception, "Cannot multiply an XML node by a value");
+ case POINTER:
+ throw_(value_exception, "Cannot multiply a pointer by a value");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot multiply a sequence by a value");
+
+ default:
+ assert(0);
+ break;
+ }
+ return *this;
+}
+
+value_t& value_t::operator/=(const value_t& val)
+{
+ if (val.type == BOOLEAN)
+ throw_(value_exception, "Cannot divide a boolean by a value");
+ else if (val.type == DATETIME)
+ throw_(value_exception, "Cannot divide a date/time by a value");
+ else if (val.type == STRING)
+ throw_(value_exception, "Cannot divide a string by a value");
+ else if (val.type == POINTER)
+ throw_(value_exception, "Cannot divide a pointer by a value");
+ else if (val.type == SEQUENCE)
+ throw_(value_exception, "Cannot divide a value by a sequence");
+ else if (val.type == XML_NODE) // recurse
+ return *this /= (*(xml::node_t **) val.data)->to_value();
+
+ switch (type) {
+ case BOOLEAN:
+ throw_(value_exception, "Cannot divide a value by a boolean");
+
+ case INTEGER:
+ switch (val.type) {
+ case INTEGER:
+ *((long *) data) /= *((long *) val.data);
+ break;
+ case AMOUNT:
+ in_place_cast(AMOUNT);
+ *((amount_t *) data) /= *((amount_t *) val.data);
+ break;
+ case BALANCE:
+ in_place_cast(BALANCE);
+ *((balance_t *) data) /= *((balance_t *) val.data);
+ break;
+ case BALANCE_PAIR:
+ in_place_cast(BALANCE_PAIR);
+ *((balance_pair_t *) data) /= *((balance_pair_t *) val.data);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case AMOUNT:
+ switch (val.type) {
+ case INTEGER:
+ *((amount_t *) data) /= *((long *) val.data);
+ break;
+ case AMOUNT:
+ *((amount_t *) data) /= *((amount_t *) val.data);
+ break;
+ case BALANCE:
+ in_place_cast(BALANCE);
+ *((balance_t *) data) /= *((balance_t *) val.data);
+ break;
+ case BALANCE_PAIR:
+ in_place_cast(BALANCE_PAIR);
+ *((balance_pair_t *) data) /= *((balance_pair_t *) val.data);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case BALANCE:
+ switch (val.type) {
+ case INTEGER:
+ *((balance_t *) data) /= *((long *) val.data);
+ break;
+ case AMOUNT:
+ *((balance_t *) data) /= *((amount_t *) val.data);
+ break;
+ case BALANCE:
+ *((balance_t *) data) /= *((balance_t *) val.data);
+ break;
+ case BALANCE_PAIR:
+ in_place_cast(BALANCE_PAIR);
+ *((balance_pair_t *) data) /= *((balance_pair_t *) val.data);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case BALANCE_PAIR:
+ switch (val.type) {
+ case INTEGER:
+ *((balance_pair_t *) data) /= *((long *) val.data);
+ break;
+ case AMOUNT:
+ *((balance_pair_t *) data) /= *((amount_t *) val.data);
+ break;
+ case BALANCE:
+ *((balance_pair_t *) data) /= *((balance_t *) val.data);
+ break;
+ case BALANCE_PAIR:
+ *((balance_pair_t *) data) /= *((balance_pair_t *) val.data);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case STRING:
+ throw_(value_exception, "Cannot divide a value from a string");
+ case XML_NODE:
+ throw_(value_exception, "Cannot divide a value from an XML node");
+ case POINTER:
+ throw_(value_exception, "Cannot divide a value from a pointer");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot divide a value from a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ return *this;
+}
+
+template <>
+value_t::operator bool() const
+{
+ switch (type) {
+ case BOOLEAN:
+ return *(bool *) data;
+ case INTEGER:
+ return *(long *) data;
+ case DATETIME:
+ return is_valid_moment(*((moment_t *) data));
+ case AMOUNT:
+ return *(amount_t *) data;
+ case BALANCE:
+ return *(balance_t *) data;
+ case BALANCE_PAIR:
+ return *(balance_pair_t *) data;
+ case STRING:
+ return ! (**((string **) data)).empty();
+ case XML_NODE:
+ return (*(xml::node_t **) data)->to_value().to_boolean();
+ case POINTER:
+ return *(void **) data != NULL;
+ case SEQUENCE:
+ return (*(sequence_t **) data != NULL &&
+ ! (*(sequence_t **) data)->empty());
+
+ default:
+ assert(0);
+ break;
+ }
+ assert(0);
+ return 0;
+}
+
+template <>
+value_t::operator long() const
+{
+ switch (type) {
+ case BOOLEAN:
+ throw_(value_exception, "Cannot convert a boolean to an integer");
+ case INTEGER:
+ return *((long *) data);
+ case DATETIME:
+ throw_(value_exception, "Cannot convert a date/time to an integer");
+ case AMOUNT:
+ return *((amount_t *) data);
+ case BALANCE:
+ throw_(value_exception, "Cannot convert a balance to an integer");
+ case BALANCE_PAIR:
+ throw_(value_exception, "Cannot convert a balance pair to an integer");
+ case STRING:
+ throw_(value_exception, "Cannot convert a string to an integer");
+ case XML_NODE:
+ return (*(xml::node_t **) data)->to_value().to_integer();
+ case POINTER:
+ throw_(value_exception, "Cannot convert a pointer to an integer");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot convert a sequence to an integer");
+
+ default:
+ assert(0);
+ break;
+ }
+ assert(0);
+ return 0;
+}
+
+template <>
+value_t::operator moment_t() const
+{
+ switch (type) {
+ case BOOLEAN:
+ throw_(value_exception, "Cannot convert a boolean to a date/time");
+ case INTEGER:
+ throw_(value_exception, "Cannot convert an integer to a date/time");
+ case DATETIME:
+ return *((moment_t *) data);
+ case AMOUNT:
+ throw_(value_exception, "Cannot convert an amount to a date/time");
+ case BALANCE:
+ throw_(value_exception, "Cannot convert a balance to a date/time");
+ case BALANCE_PAIR:
+ throw_(value_exception, "Cannot convert a balance pair to a date/time");
+ case STRING:
+ throw_(value_exception, "Cannot convert a string to a date/time");
+ case XML_NODE:
+ return (*(xml::node_t **) data)->to_value().to_datetime();
+ case POINTER:
+ throw_(value_exception, "Cannot convert a pointer to a date/time");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot convert a sequence to a date/time");
+
+ default:
+ assert(0);
+ break;
+ }
+ assert(0);
+ return moment_t();
+}
+
+template <>
+value_t::operator double() const
+{
+ switch (type) {
+ case BOOLEAN:
+ throw_(value_exception, "Cannot convert a boolean to a double");
+ case INTEGER:
+ return *((long *) data);
+ case DATETIME:
+ throw_(value_exception, "Cannot convert a date/time to a double");
+ case AMOUNT:
+ return *((amount_t *) data);
+ case BALANCE:
+ throw_(value_exception, "Cannot convert a balance to a double");
+ case BALANCE_PAIR:
+ throw_(value_exception, "Cannot convert a balance pair to a double");
+ case STRING:
+ throw_(value_exception, "Cannot convert a string to a double");
+ case XML_NODE:
+ return (*(xml::node_t **) data)->to_value().to_amount().number();
+ case POINTER:
+ throw_(value_exception, "Cannot convert a pointer to a double");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot convert a sequence to a double");
+
+ default:
+ assert(0);
+ break;
+ }
+ assert(0);
+ return 0;
+}
+
+template <>
+value_t::operator string() const
+{
+ switch (type) {
+ case BOOLEAN:
+ case INTEGER:
+ case DATETIME:
+ case AMOUNT:
+ case BALANCE:
+ case BALANCE_PAIR: {
+ value_t temp(*this);
+ temp.in_place_cast(STRING);
+ return temp;
+ }
+ case STRING:
+ return **(string **) data;
+ case XML_NODE:
+ return (*(xml::node_t **) data)->to_value().to_string();
+
+ case POINTER:
+ throw_(value_exception, "Cannot convert a pointer to a string");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot convert a sequence to a string");
+
+ default:
+ assert(0);
+ break;
+ }
+ assert(0);
+ return 0;
+}
+
+#define DEF_VALUE_CMP_OP(OP) \
+bool value_t::operator OP(const value_t& val) \
+{ \
+ switch (type) { \
+ case BOOLEAN: \
+ switch (val.type) { \
+ case BOOLEAN: \
+ return *((bool *) data) OP *((bool *) val.data); \
+ \
+ case INTEGER: \
+ return *((bool *) data) OP bool(*((long *) val.data)); \
+ \
+ case DATETIME: \
+ throw_(value_exception, "Cannot compare a boolean to a date/time"); \
+ \
+ case AMOUNT: \
+ return *((bool *) data) OP bool(*((amount_t *) val.data)); \
+ \
+ case BALANCE: \
+ return *((bool *) data) OP bool(*((balance_t *) val.data)); \
+ \
+ case BALANCE_PAIR: \
+ return *((bool *) data) OP bool(*((balance_pair_t *) val.data)); \
+ \
+ case STRING: \
+ throw_(value_exception, "Cannot compare a boolean to a string"); \
+ \
+ case XML_NODE: \
+ return *this OP (*(xml::node_t **) data)->to_value(); \
+ \
+ case POINTER: \
+ throw_(value_exception, "Cannot compare a boolean to a pointer"); \
+ case SEQUENCE: \
+ throw_(value_exception, "Cannot compare a boolean to a sequence"); \
+ \
+ default: \
+ assert(0); \
+ break; \
+ } \
+ break; \
+ \
+ case INTEGER: \
+ switch (val.type) { \
+ case BOOLEAN: \
+ return (*((long *) data) OP \
+ ((long) *((bool *) val.data))); \
+ \
+ case INTEGER: \
+ return (*((long *) data) OP *((long *) val.data)); \
+ \
+ case DATETIME: \
+ throw_(value_exception, "Cannot compare an integer to a date/time"); \
+ \
+ case AMOUNT: \
+ return (amount_t(*((long *) data)) OP \
+ *((amount_t *) val.data)); \
+ \
+ case BALANCE: \
+ return (balance_t(*((long *) data)) OP \
+ *((balance_t *) val.data)); \
+ \
+ case BALANCE_PAIR: \
+ return (balance_pair_t(*((long *) data)) OP \
+ *((balance_pair_t *) val.data)); \
+ \
+ case STRING: \
+ throw_(value_exception, "Cannot compare an integer to a string"); \
+ \
+ case XML_NODE: \
+ return *this OP (*(xml::node_t **) data)->to_value(); \
+ \
+ case POINTER: \
+ throw_(value_exception, "Cannot compare an integer to a pointer"); \
+ case SEQUENCE: \
+ throw_(value_exception, "Cannot compare an integer to a sequence"); \
+ \
+ default: \
+ assert(0); \
+ break; \
+ } \
+ break; \
+ \
+ case DATETIME: \
+ switch (val.type) { \
+ case BOOLEAN: \
+ throw_(value_exception, "Cannot compare a date/time to a boolean"); \
+ \
+ case INTEGER: \
+ throw_(value_exception, "Cannot compare a date/time to an integer"); \
+ \
+ case DATETIME: \
+ return *((moment_t *) data) OP *((moment_t *) val.data); \
+ \
+ case AMOUNT: \
+ throw_(value_exception, "Cannot compare a date/time to an amount"); \
+ case BALANCE: \
+ throw_(value_exception, "Cannot compare a date/time to a balance"); \
+ case BALANCE_PAIR: \
+ throw_(value_exception, "Cannot compare a date/time to a balance pair"); \
+ case STRING: \
+ throw_(value_exception, "Cannot compare a date/time to a string"); \
+ \
+ case XML_NODE: \
+ return *this OP (*(xml::node_t **) data)->to_value(); \
+ \
+ case POINTER: \
+ throw_(value_exception, "Cannot compare a date/time to a pointer"); \
+ case SEQUENCE: \
+ throw_(value_exception, "Cannot compare a date/time to a sequence"); \
+ \
+ default: \
+ assert(0); \
+ break; \
+ } \
+ break; \
+ \
+ case AMOUNT: \
+ switch (val.type) { \
+ case BOOLEAN: \
+ throw_(value_exception, "Cannot compare an amount to a boolean"); \
+ \
+ case INTEGER: \
+ return (*((amount_t *) data) OP \
+ amount_t(*((long *) val.data))); \
+ \
+ case DATETIME: \
+ throw_(value_exception, "Cannot compare an amount to a date/time"); \
+ \
+ case AMOUNT: \
+ return *((amount_t *) data) OP *((amount_t *) val.data); \
+ \
+ case BALANCE: \
+ return (balance_t(*((amount_t *) data)) OP \
+ *((balance_t *) val.data)); \
+ \
+ case BALANCE_PAIR: \
+ return (balance_t(*((amount_t *) data)) OP \
+ *((balance_pair_t *) val.data)); \
+ \
+ case STRING: \
+ throw_(value_exception, "Cannot compare an amount to a string"); \
+ \
+ case XML_NODE: \
+ return *this OP (*(xml::node_t **) data)->to_value(); \
+ \
+ case POINTER: \
+ throw_(value_exception, "Cannot compare an amount to a pointer"); \
+ case SEQUENCE: \
+ throw_(value_exception, "Cannot compare an amount to a sequence"); \
+ \
+ default: \
+ assert(0); \
+ break; \
+ } \
+ break; \
+ \
+ case BALANCE: \
+ switch (val.type) { \
+ case BOOLEAN: \
+ throw_(value_exception, "Cannot compare a balance to a boolean"); \
+ \
+ case INTEGER: \
+ return *((balance_t *) data) OP *((long *) val.data); \
+ \
+ case DATETIME: \
+ throw_(value_exception, "Cannot compare a balance to a date/time"); \
+ \
+ case AMOUNT: \
+ return *((balance_t *) data) OP *((amount_t *) val.data); \
+ \
+ case BALANCE: \
+ return *((balance_t *) data) OP *((balance_t *) val.data); \
+ \
+ case BALANCE_PAIR: \
+ return (*((balance_t *) data) OP \
+ ((balance_pair_t *) val.data)->quantity); \
+ \
+ case STRING: \
+ throw_(value_exception, "Cannot compare a balance to a string"); \
+ \
+ case XML_NODE: \
+ return *this OP (*(xml::node_t **) data)->to_value(); \
+ \
+ case POINTER: \
+ throw_(value_exception, "Cannot compare a balance to a pointer"); \
+ case SEQUENCE: \
+ throw_(value_exception, "Cannot compare a balance to a sequence"); \
+ \
+ default: \
+ assert(0); \
+ break; \
+ } \
+ break; \
+ \
+ case BALANCE_PAIR: \
+ switch (val.type) { \
+ case BOOLEAN: \
+ throw_(value_exception, "Cannot compare a balance pair to a boolean"); \
+ \
+ case INTEGER: \
+ return (((balance_pair_t *) data)->quantity OP \
+ *((long *) val.data)); \
+ \
+ case DATETIME: \
+ throw_(value_exception, "Cannot compare a balance pair to a date/time"); \
+ \
+ case AMOUNT: \
+ return (((balance_pair_t *) data)->quantity OP \
+ *((amount_t *) val.data)); \
+ \
+ case BALANCE: \
+ return (((balance_pair_t *) data)->quantity OP \
+ *((balance_t *) val.data)); \
+ \
+ case BALANCE_PAIR: \
+ return (*((balance_pair_t *) data) OP \
+ *((balance_pair_t *) val.data)); \
+ \
+ case STRING: \
+ throw_(value_exception, "Cannot compare a balance pair to a string"); \
+ \
+ case XML_NODE: \
+ return *this OP (*(xml::node_t **) data)->to_value(); \
+ \
+ case POINTER: \
+ throw_(value_exception, "Cannot compare a balance pair to a pointer"); \
+ case SEQUENCE: \
+ throw_(value_exception, "Cannot compare a balance pair to a sequence"); \
+ \
+ default: \
+ assert(0); \
+ break; \
+ } \
+ break; \
+ \
+ case STRING: \
+ switch (val.type) { \
+ case BOOLEAN: \
+ throw_(value_exception, "Cannot compare a string to a boolean"); \
+ case INTEGER: \
+ throw_(value_exception, "Cannot compare a string to an integer"); \
+ case DATETIME: \
+ throw_(value_exception, "Cannot compare a string to a date/time"); \
+ case AMOUNT: \
+ throw_(value_exception, "Cannot compare a string to an amount"); \
+ case BALANCE: \
+ throw_(value_exception, "Cannot compare a string to a balance"); \
+ case BALANCE_PAIR: \
+ throw_(value_exception, "Cannot compare a string to a balance pair"); \
+ \
+ case STRING: \
+ return (**((string **) data) OP \
+ **((string **) val.data)); \
+ \
+ case XML_NODE: \
+ return *this OP (*(xml::node_t **) data)->to_value(); \
+ \
+ case POINTER: \
+ throw_(value_exception, "Cannot compare a string to a pointer"); \
+ case SEQUENCE: \
+ throw_(value_exception, "Cannot compare a string to a sequence"); \
+ \
+ default: \
+ assert(0); \
+ break; \
+ } \
+ break; \
+ \
+ case XML_NODE: \
+ switch (val.type) { \
+ case BOOLEAN: \
+ return (*(xml::node_t **) data)->to_value() OP *this; \
+ case INTEGER: \
+ return (*(xml::node_t **) data)->to_value() OP *this; \
+ case DATETIME: \
+ return (*(xml::node_t **) data)->to_value() OP *this; \
+ case AMOUNT: \
+ return (*(xml::node_t **) data)->to_value() OP *this; \
+ case BALANCE: \
+ return (*(xml::node_t **) data)->to_value() OP *this; \
+ case BALANCE_PAIR: \
+ return (*(xml::node_t **) data)->to_value() OP *this; \
+ case STRING: \
+ return (*(xml::node_t **) data)->to_value() OP *this; \
+ \
+ case XML_NODE: \
+ return ((*(xml::node_t **) data)->to_value() OP \
+ (*(xml::node_t **) val.data)->to_value()); \
+ \
+ case POINTER: \
+ throw_(value_exception, "Cannot compare an XML node to a pointer"); \
+ case SEQUENCE: \
+ throw_(value_exception, "Cannot compare an XML node to a sequence"); \
+ \
+ default: \
+ assert(0); \
+ break; \
+ } \
+ break; \
+ \
+ case POINTER: \
+ switch (val.type) { \
+ case BOOLEAN: \
+ throw_(value_exception, "Cannot compare a pointer to a boolean"); \
+ case INTEGER: \
+ throw_(value_exception, "Cannot compare a pointer to an integer"); \
+ case DATETIME: \
+ throw_(value_exception, "Cannot compare a pointer to a date/time"); \
+ case AMOUNT: \
+ throw_(value_exception, "Cannot compare a pointer to an amount"); \
+ case BALANCE: \
+ throw_(value_exception, "Cannot compare a pointer to a balance"); \
+ case BALANCE_PAIR: \
+ throw_(value_exception, "Cannot compare a pointer to a balance pair"); \
+ case STRING: \
+ throw_(value_exception, "Cannot compare a pointer to a string node"); \
+ case XML_NODE: \
+ throw_(value_exception, "Cannot compare a pointer to an XML node"); \
+ case POINTER: \
+ return (*((void **) data) OP *((void **) val.data)); \
+ case SEQUENCE: \
+ throw_(value_exception, "Cannot compare a pointer to a sequence"); \
+ \
+ default: \
+ assert(0); \
+ break; \
+ } \
+ break; \
+ \
+ case SEQUENCE: \
+ throw_(value_exception, "Cannot compare a value to a sequence"); \
+ \
+ default: \
+ assert(0); \
+ break; \
+ } \
+ return *this; \
+}
+
+DEF_VALUE_CMP_OP(==)
+DEF_VALUE_CMP_OP(<)
+DEF_VALUE_CMP_OP(<=)
+DEF_VALUE_CMP_OP(>)
+DEF_VALUE_CMP_OP(>=)
+
+void value_t::in_place_cast(type_t cast_type)
+{
+ switch (type) {
+ case BOOLEAN:
+ switch (cast_type) {
+ case BOOLEAN:
+ break;
+ case INTEGER:
+ throw_(value_exception, "Cannot convert a boolean to an integer");
+ case DATETIME:
+ throw_(value_exception, "Cannot convert a boolean to a date/time");
+ case AMOUNT:
+ throw_(value_exception, "Cannot convert a boolean to an amount");
+ case BALANCE:
+ throw_(value_exception, "Cannot convert a boolean to a balance");
+ case BALANCE_PAIR:
+ throw_(value_exception, "Cannot convert a boolean to a balance pair");
+ case STRING:
+ *(string **) data = new string(*((bool *) data) ? "true" : "false");
+ break;
+ case XML_NODE:
+ throw_(value_exception, "Cannot convert a boolean to an XML node");
+ case POINTER:
+ throw_(value_exception, "Cannot convert a boolean to a pointer");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot convert a boolean to a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case INTEGER:
+ switch (cast_type) {
+ case BOOLEAN:
+ *((bool *) data) = *((long *) data);
+ break;
+ case INTEGER:
+ break;
+ case DATETIME:
+ throw_(value_exception, "Cannot convert an integer to a date/time");
+
+ case AMOUNT:
+ new((amount_t *)data) amount_t(*((long *) data));
+ break;
+ case BALANCE:
+ new((balance_t *)data) balance_t(*((long *) data));
+ break;
+ case BALANCE_PAIR:
+ new((balance_pair_t *)data) balance_pair_t(*((long *) data));
+ break;
+ case STRING: {
+ char buf[32];
+ std::sprintf(buf, "%ld", *(long *) data);
+ *(string **) data = new string(buf);
+ break;
+ }
+ case XML_NODE:
+ throw_(value_exception, "Cannot convert an integer to an XML node");
+ case POINTER:
+ throw_(value_exception, "Cannot convert an integer to a pointer");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot convert an integer to a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case DATETIME:
+ switch (cast_type) {
+ case BOOLEAN:
+ *((bool *) data) = is_valid_moment(*((moment_t *) data));
+ break;
+ case INTEGER:
+ throw_(value_exception, "Cannot convert a date/time to an integer");
+ case DATETIME:
+ break;
+ case AMOUNT:
+ throw_(value_exception, "Cannot convert a date/time to an amount");
+ case BALANCE:
+ throw_(value_exception, "Cannot convert a date/time to a balance");
+ case BALANCE_PAIR:
+ throw_(value_exception, "Cannot convert a date/time to a balance pair");
+ case STRING:
+ throw_(value_exception, "Cannot convert a date/time to a string");
+ case XML_NODE:
+ throw_(value_exception, "Cannot convert a date/time to an XML node");
+ case POINTER:
+ throw_(value_exception, "Cannot convert a date/time to a pointer");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot convert a date/time to a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case AMOUNT:
+ switch (cast_type) {
+ case BOOLEAN: {
+ bool temp = *((amount_t *) data);
+ destroy();
+ *((bool *)data) = temp;
+ break;
+ }
+ case INTEGER: {
+ long temp = *((amount_t *) data);
+ destroy();
+ *((long *)data) = temp;
+ break;
+ }
+ case DATETIME:
+ throw_(value_exception, "Cannot convert an amount to a date/time");
+ case AMOUNT:
+ break;
+ case BALANCE: {
+ amount_t temp = *((amount_t *) data);
+ destroy();
+ new((balance_t *)data) balance_t(temp);
+ break;
+ }
+ case BALANCE_PAIR: {
+ amount_t temp = *((amount_t *) data);
+ destroy();
+ new((balance_pair_t *)data) balance_pair_t(temp);
+ break;
+ }
+ case STRING: {
+ std::ostringstream out;
+ out << *(amount_t *) data;
+ destroy();
+ *(string **) data = new string(out.str());
+ break;
+ }
+ case XML_NODE:
+ throw_(value_exception, "Cannot convert an amount to an XML node");
+ case POINTER:
+ throw_(value_exception, "Cannot convert an amount to a pointer");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot convert an amount to a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case BALANCE:
+ switch (cast_type) {
+ case BOOLEAN: {
+ bool temp = *((balance_t *) data);
+ destroy();
+ *((bool *)data) = temp;
+ break;
+ }
+ case INTEGER:
+ throw_(value_exception, "Cannot convert a balance to an integer");
+ case DATETIME:
+ throw_(value_exception, "Cannot convert a balance to a date/time");
+
+ case AMOUNT: {
+ balance_t * temp = (balance_t *) data;
+ if (temp->amounts.size() == 1) {
+ amount_t amt = (*temp->amounts.begin()).second;
+ destroy();
+ new((amount_t *)data) amount_t(amt);
+ }
+ else if (temp->amounts.size() == 0) {
+ new((amount_t *)data) amount_t();
+ }
+ else {
+ throw_(value_exception, "Cannot convert a balance with "
+ "multiple commodities to an amount");
+ }
+ break;
+ }
+ case BALANCE:
+ break;
+ case BALANCE_PAIR: {
+ balance_t temp = *((balance_t *) data);
+ destroy();
+ new((balance_pair_t *)data) balance_pair_t(temp);
+ break;
+ }
+ case STRING:
+ throw_(value_exception, "Cannot convert a balance to a string");
+ case XML_NODE:
+ throw_(value_exception, "Cannot convert a balance to an XML node");
+ case POINTER:
+ throw_(value_exception, "Cannot convert a balance to a pointer");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot convert a balance to a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case BALANCE_PAIR:
+ switch (cast_type) {
+ case BOOLEAN: {
+ bool temp = *((balance_pair_t *) data);
+ destroy();
+ *((bool *)data) = temp;
+ break;
+ }
+ case INTEGER:
+ throw_(value_exception, "Cannot convert a balance pair to an integer");
+ case DATETIME:
+ throw_(value_exception, "Cannot convert a balance pair to a date/time");
+
+ case AMOUNT: {
+ balance_t * temp = &((balance_pair_t *) data)->quantity;
+ if (temp->amounts.size() == 1) {
+ amount_t amt = (*temp->amounts.begin()).second;
+ destroy();
+ new((amount_t *)data) amount_t(amt);
+ }
+ else if (temp->amounts.size() == 0) {
+ new((amount_t *)data) amount_t();
+ }
+ else {
+ throw_(value_exception, "Cannot convert a balance pair with "
+ "multiple commodities to an amount");
+ }
+ break;
+ }
+ case BALANCE: {
+ balance_t temp = ((balance_pair_t *) data)->quantity;
+ destroy();
+ new((balance_t *)data) balance_t(temp);
+ break;
+ }
+ case BALANCE_PAIR:
+ break;
+ case STRING:
+ throw_(value_exception, "Cannot convert a balance pair to a string");
+ case XML_NODE:
+ throw_(value_exception, "Cannot convert a balance pair to an XML node");
+ case POINTER:
+ throw_(value_exception, "Cannot convert a balance pair to a pointer");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot convert a balance pair to a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case STRING:
+ switch (cast_type) {
+ case BOOLEAN: {
+ if (**(string **) data == "true") {
+ destroy();
+ *(bool *) data = true;
+ }
+ else if (**(string **) data == "false") {
+ destroy();
+ *(bool *) data = false;
+ }
+ else {
+ throw_(value_exception, "Cannot convert string to an boolean");
+ }
+ break;
+ }
+ case INTEGER: {
+ int l = (*(string **) data)->length();
+ const char * p = (*(string **) data)->c_str();
+ bool alldigits = true;
+ for (int i = 0; i < l; i++)
+ if (! std::isdigit(p[i])) {
+ alldigits = false;
+ break;
+ }
+ if (alldigits) {
+ long temp = std::atol((*(string **) data)->c_str());
+ destroy();
+ *(long *) data = temp;
+ } else {
+ throw_(value_exception, "Cannot convert string to an integer");
+ }
+ break;
+ }
+
+ case DATETIME:
+ throw_(value_exception, "Cannot convert a string to a date/time");
+
+ case AMOUNT: {
+ amount_t temp = **(string **) data;
+ destroy();
+ new((amount_t *)data) amount_t(temp);
+ break;
+ }
+ case BALANCE:
+ throw_(value_exception, "Cannot convert a string to a balance");
+ case BALANCE_PAIR:
+ throw_(value_exception, "Cannot convert a string to a balance pair");
+ case STRING:
+ break;
+ case XML_NODE:
+ throw_(value_exception, "Cannot convert a string to an XML node");
+ case POINTER:
+ throw_(value_exception, "Cannot convert a string to a pointer");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot convert a string to a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case XML_NODE:
+ switch (cast_type) {
+ case BOOLEAN:
+ case INTEGER:
+ case DATETIME:
+ case AMOUNT:
+ case BALANCE:
+ case BALANCE_PAIR:
+ case STRING:
+ *this = (*(xml::node_t **) data)->to_value();
+ break;
+ case XML_NODE:
+ break;
+ case POINTER:
+ throw_(value_exception, "Cannot convert an XML node to a pointer");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot convert an XML node to a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case POINTER:
+ switch (cast_type) {
+ case BOOLEAN:
+ throw_(value_exception, "Cannot convert a pointer to a boolean");
+ case INTEGER:
+ throw_(value_exception, "Cannot convert a pointer to an integer");
+ case DATETIME:
+ throw_(value_exception, "Cannot convert a pointer to a date/time");
+ case AMOUNT:
+ throw_(value_exception, "Cannot convert a pointer to an amount");
+ case BALANCE:
+ throw_(value_exception, "Cannot convert a pointer to a balance");
+ case BALANCE_PAIR:
+ throw_(value_exception, "Cannot convert a pointer to a balance pair");
+ case STRING:
+ throw_(value_exception, "Cannot convert a pointer to a string");
+ case XML_NODE:
+ throw_(value_exception, "Cannot convert a pointer to an XML node");
+ case POINTER:
+ break;
+ case SEQUENCE:
+ throw_(value_exception, "Cannot convert a pointer to a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case SEQUENCE:
+ switch (cast_type) {
+ case BOOLEAN:
+ throw_(value_exception, "Cannot convert a sequence to a boolean");
+ case INTEGER:
+ throw_(value_exception, "Cannot convert a sequence to an integer");
+ case DATETIME:
+ throw_(value_exception, "Cannot convert a sequence to a date/time");
+ case AMOUNT:
+ throw_(value_exception, "Cannot convert a sequence to an amount");
+ case BALANCE:
+ throw_(value_exception, "Cannot convert a sequence to a balance");
+ case BALANCE_PAIR:
+ throw_(value_exception, "Cannot convert a sequence to a balance pair");
+ case STRING:
+ throw_(value_exception, "Cannot convert a sequence to a string");
+ case XML_NODE:
+ throw_(value_exception, "Cannot compare a sequence to an XML node");
+ case POINTER:
+ throw_(value_exception, "Cannot convert a sequence to a pointer");
+ case SEQUENCE:
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ type = cast_type;
+}
+
+void value_t::in_place_negate()
+{
+ switch (type) {
+ case BOOLEAN:
+ *((bool *) data) = ! *((bool *) data);
+ break;
+ case INTEGER:
+ *((long *) data) = - *((long *) data);
+ break;
+ case DATETIME:
+ throw_(value_exception, "Cannot negate a date/time");
+ case AMOUNT:
+ ((amount_t *) data)->in_place_negate();
+ break;
+ case BALANCE:
+ ((balance_t *) data)->in_place_negate();
+ break;
+ case BALANCE_PAIR:
+ ((balance_pair_t *) data)->in_place_negate();
+ break;
+ case STRING:
+ throw_(value_exception, "Cannot negate a string");
+ case XML_NODE:
+ *this = (*(xml::node_t **) data)->to_value();
+ in_place_negate();
+ break;
+ case POINTER:
+ throw_(value_exception, "Cannot negate a pointer");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot negate a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+}
+
+void value_t::in_place_abs()
+{
+ switch (type) {
+ case BOOLEAN:
+ break;
+ case INTEGER:
+ if (*((long *) data) < 0)
+ *((long *) data) = - *((long *) data);
+ break;
+ case DATETIME:
+ break;
+ case AMOUNT:
+ ((amount_t *) data)->abs();
+ break;
+ case BALANCE:
+ ((balance_t *) data)->abs();
+ break;
+ case BALANCE_PAIR:
+ ((balance_pair_t *) data)->abs();
+ break;
+ case STRING:
+ throw_(value_exception, "Cannot take the absolute value of a string");
+ case XML_NODE:
+ *this = (*(xml::node_t **) data)->to_value();
+ in_place_abs();
+ break;
+ case POINTER:
+ throw_(value_exception, "Cannot take the absolute value of a pointer");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot take the absolute value of a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+}
+
+value_t value_t::value(const moment_t& moment) const
+{
+ switch (type) {
+ case BOOLEAN:
+ throw_(value_exception, "Cannot find the value of a boolean");
+ case DATETIME:
+ throw_(value_exception, "Cannot find the value of a date/time");
+ case INTEGER:
+ return *this;
+ case AMOUNT:
+ return ((amount_t *) data)->value(moment);
+ case BALANCE:
+ return ((balance_t *) data)->value(moment);
+ case BALANCE_PAIR:
+ return ((balance_pair_t *) data)->quantity.value(moment);
+ case STRING:
+ throw_(value_exception, "Cannot find the value of a string");
+ case XML_NODE:
+ return (*(xml::node_t **) data)->to_value().value(moment);
+ case POINTER:
+ throw_(value_exception, "Cannot find the value of a pointer");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot find the value of a sequence");
+ default:
+ assert(0);
+ return value_t();
+ }
+}
+
+void value_t::in_place_reduce()
+{
+ switch (type) {
+ case BOOLEAN:
+ case DATETIME:
+ case INTEGER:
+ break;
+ case AMOUNT:
+ ((amount_t *) data)->in_place_reduce();
+ break;
+ case BALANCE:
+ ((balance_t *) data)->in_place_reduce();
+ break;
+ case BALANCE_PAIR:
+ ((balance_pair_t *) data)->in_place_reduce();
+ break;
+ case STRING:
+ throw_(value_exception, "Cannot reduce a string");
+ case XML_NODE:
+ *this = (*(xml::node_t **) data)->to_value();
+ in_place_reduce(); // recurse
+ break;
+ case POINTER:
+ throw_(value_exception, "Cannot reduce a pointer");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot reduce a sequence");
+ }
+}
+
+value_t value_t::round() const
+{
+ switch (type) {
+ case BOOLEAN:
+ throw_(value_exception, "Cannot round a boolean");
+ case DATETIME:
+ throw_(value_exception, "Cannot round a date/time");
+ case INTEGER:
+ return *this;
+ case AMOUNT:
+ return ((amount_t *) data)->round();
+ case BALANCE:
+ return ((balance_t *) data)->round();
+ case BALANCE_PAIR:
+ return ((balance_pair_t *) data)->round();
+ case STRING:
+ throw_(value_exception, "Cannot round a string");
+ case XML_NODE:
+ return (*(xml::node_t **) data)->to_value().round();
+ case POINTER:
+ throw_(value_exception, "Cannot round a pointer");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot round a sequence");
+ }
+ assert(0);
+ return value_t();
+}
+
+value_t value_t::unround() const
+{
+ switch (type) {
+ case BOOLEAN:
+ throw_(value_exception, "Cannot un-round a boolean");
+ case DATETIME:
+ throw_(value_exception, "Cannot un-round a date/time");
+ case INTEGER:
+ return *this;
+ case AMOUNT:
+ return ((amount_t *) data)->unround();
+ case BALANCE:
+ return ((balance_t *) data)->unround();
+ case BALANCE_PAIR:
+ return ((balance_pair_t *) data)->unround();
+ case STRING:
+ throw_(value_exception, "Cannot un-round a string");
+ case XML_NODE:
+ return (*(xml::node_t **) data)->to_value().unround();
+ case POINTER:
+ throw_(value_exception, "Cannot un-round a pointer");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot un-round a sequence");
+ }
+ assert(0);
+ return value_t();
+}
+
+value_t value_t::price() const
+{
+ switch (type) {
+ case BOOLEAN:
+ throw_(value_exception, "Cannot find the price of a boolean");
+ case INTEGER:
+ return *this;
+ case DATETIME:
+ throw_(value_exception, "Cannot find the price of a date/time");
+
+ case AMOUNT:
+ return ((amount_t *) data)->price();
+ case BALANCE:
+ return ((balance_t *) data)->price();
+ case BALANCE_PAIR:
+ return ((balance_pair_t *) data)->quantity.price();
+
+ case STRING:
+ throw_(value_exception, "Cannot find the price of a string");
+
+ case XML_NODE:
+ return (*(xml::node_t **) data)->to_value().price();
+
+ case POINTER:
+ throw_(value_exception, "Cannot find the price of a pointer");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot find the price of a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ assert(0);
+ return value_t();
+}
+
+value_t value_t::date() const
+{
+ switch (type) {
+ case BOOLEAN:
+ throw_(value_exception, "Cannot find the date of a boolean");
+ case INTEGER:
+ throw_(value_exception, "Cannot find the date of an integer");
+
+ case DATETIME:
+ return *this;
+
+ case AMOUNT:
+ return ((amount_t *) data)->date();
+ case BALANCE:
+ return ((balance_t *) data)->date();
+ case BALANCE_PAIR:
+ return ((balance_pair_t *) data)->quantity.date();
+
+ case STRING:
+ throw_(value_exception, "Cannot find the date of a string");
+
+ case XML_NODE:
+ return (*(xml::node_t **) data)->to_value().date();
+
+ case POINTER:
+ throw_(value_exception, "Cannot find the date of a pointer");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot find the date of a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ assert(0);
+ return value_t();
+}
+
+value_t value_t::strip_annotations(const bool keep_price,
+ const bool keep_date,
+ const bool keep_tag) const
+{
+ switch (type) {
+ case BOOLEAN:
+ case INTEGER:
+ case DATETIME:
+ case STRING:
+ case XML_NODE:
+ case POINTER:
+ return *this;
+
+ case SEQUENCE:
+ assert(0); // jww (2006-09-28): strip them all!
+ break;
+
+ case AMOUNT:
+ return ((amount_t *) data)->strip_annotations
+ (keep_price, keep_date, keep_tag);
+ case BALANCE:
+ return ((balance_t *) data)->strip_annotations
+ (keep_price, keep_date, keep_tag);
+ case BALANCE_PAIR:
+ return ((balance_pair_t *) data)->quantity.strip_annotations
+ (keep_price, keep_date, keep_tag);
+
+ default:
+ assert(0);
+ break;
+ }
+ assert(0);
+ return value_t();
+}
+
+value_t value_t::cost() const
+{
+ switch (type) {
+ case BOOLEAN:
+ throw_(value_exception, "Cannot find the cost of a boolean");
+ case INTEGER:
+ case AMOUNT:
+ case BALANCE:
+ return *this;
+ case DATETIME:
+ throw_(value_exception, "Cannot find the cost of a date/time");
+
+ case BALANCE_PAIR:
+ assert(((balance_pair_t *) data)->cost);
+ if (((balance_pair_t *) data)->cost)
+ return *(((balance_pair_t *) data)->cost);
+ else
+ return ((balance_pair_t *) data)->quantity;
+
+ case STRING:
+ throw_(value_exception, "Cannot find the cost of a string");
+ case XML_NODE:
+ return (*(xml::node_t **) data)->to_value().cost();
+ case POINTER:
+ throw_(value_exception, "Cannot find the cost of a pointer");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot find the cost of a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+ assert(0);
+ return value_t();
+}
+
+value_t& value_t::add(const amount_t& amount, const amount_t * tcost)
+{
+ switch (type) {
+ case BOOLEAN:
+ throw_(value_exception, "Cannot add an amount to a boolean");
+ case DATETIME:
+ throw_(value_exception, "Cannot add an amount to a date/time");
+ case INTEGER:
+ case AMOUNT:
+ if (tcost) {
+ in_place_cast(BALANCE_PAIR);
+ return add(amount, tcost);
+ }
+ else if ((type == AMOUNT &&
+ ((amount_t *) data)->commodity() != amount.commodity()) ||
+ (type != AMOUNT && amount.commodity())) {
+ in_place_cast(BALANCE);
+ return add(amount, tcost);
+ }
+ else if (type != AMOUNT) {
+ in_place_cast(AMOUNT);
+ }
+ *((amount_t *) data) += amount;
+ break;
+
+ case BALANCE:
+ if (tcost) {
+ in_place_cast(BALANCE_PAIR);
+ return add(amount, tcost);
+ }
+ *((balance_t *) data) += amount;
+ break;
+
+ case BALANCE_PAIR:
+ ((balance_pair_t *) data)->add(amount, tcost);
+ break;
+
+ case STRING:
+ throw_(value_exception, "Cannot add an amount to a string");
+ case XML_NODE:
+ throw_(value_exception, "Cannot add an amount to an XML node");
+ case POINTER:
+ throw_(value_exception, "Cannot add an amount to a pointer");
+ case SEQUENCE:
+ throw_(value_exception, "Cannot add an amount to a sequence");
+
+ default:
+ assert(0);
+ break;
+ }
+
+ return *this;
+}
+
+void value_t::write(std::ostream& out, const int first_width,
+ const int latter_width) const
+{
+ switch (type) {
+ case BOOLEAN:
+ case DATETIME:
+ case INTEGER:
+ case AMOUNT:
+ case STRING:
+ case POINTER:
+ out << *this;
+ break;
+
+ case XML_NODE:
+ (*(xml::node_t **) data)->write(out);
+ break;
+
+ case SEQUENCE:
+ assert(0); // jww (2006-09-28): write them all out!
+ throw_(value_exception, "Cannot write out a sequence");
+
+ case BALANCE:
+ ((balance_t *) data)->write(out, first_width, latter_width);
+ break;
+ case BALANCE_PAIR:
+ ((balance_pair_t *) data)->write(out, first_width, latter_width);
+ break;
+ }
+}
+
+std::ostream& operator<<(std::ostream& out, const value_t& val)
+{
+ switch (val.type) {
+ case value_t::BOOLEAN:
+ out << (*((bool *) val.data) ? "true" : "false");
+ break;
+ case value_t::INTEGER:
+ out << *(long *) val.data;
+ break;
+ case value_t::DATETIME:
+ out << *(moment_t *) val.data;
+ break;
+ case value_t::AMOUNT:
+ out << *(amount_t *) val.data;
+ break;
+ case value_t::BALANCE:
+ out << *(balance_t *) val.data;
+ break;
+ case value_t::BALANCE_PAIR:
+ out << *(balance_pair_t *) val.data;
+ break;
+ case value_t::STRING:
+ out << **(string **) val.data;
+ break;
+ case value_t::XML_NODE:
+ if ((*(xml::node_t **) val.data)->flags & XML_NODE_IS_PARENT)
+ out << '<' << (*(xml::node_t **) val.data)->name() << '>';
+ else
+ out << (*(xml::node_t **) val.data)->text();
+ break;
+
+ case value_t::POINTER:
+ throw_(value_exception, "Cannot output a pointer value");
+
+ case value_t::SEQUENCE: {
+ out << '(';
+ bool first = true;
+ for (value_t::sequence_t::iterator
+ i = (*(value_t::sequence_t **) val.data)->begin();
+ i != (*(value_t::sequence_t **) val.data)->end();
+ i++) {
+ if (first)
+ first = false;
+ else
+ out << ", ";
+ out << *i;
+ }
+ out << ')';
+ break;
+ }
+
+ default:
+ assert(0);
+ break;
+ }
+ return out;
+}
+
+#if 0
+value_context::value_context(const value_t& _bal,
+ const string& _desc) throw()
+ : error_context(_desc), bal(new value_t(_bal)) {}
+
+value_context::~value_context() throw()
+{
+ delete bal;
+}
+
+void value_context::describe(std::ostream& out) const throw()
+{
+ if (! desc.empty())
+ out << desc << std::endl;
+
+ balance_t * ptr = NULL;
+
+ out << std::right;
+ out.width(20);
+
+ switch (bal->type) {
+ case value_t::BOOLEAN:
+ out << (*((bool *) bal->data) ? "true" : "false");
+ break;
+ case value_t::INTEGER:
+ out << *((long *) bal->data);
+ break;
+ case value_t::DATETIME:
+ out << *((moment_t *) bal->data);
+ break;
+ case value_t::AMOUNT:
+ out << *((amount_t *) bal->data);
+ break;
+ case value_t::BALANCE:
+ ptr = (balance_t *) bal->data;
+ // fall through...
+
+ case value_t::BALANCE_PAIR:
+ if (! ptr)
+ ptr = &((balance_pair_t *) bal->data)->quantity;
+
+ ptr->write(out, 20);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ out << std::endl;
+}
+#endif
+
+} // namespace ledger