2357 lines
58 KiB
C++
2357 lines
58 KiB
C++
#include "value.h"
|
|
#include "xml.h"
|
|
|
|
namespace ledger {
|
|
|
|
bool& value_t::boolean()
|
|
{
|
|
if (type == BOOLEAN) {
|
|
return *(bool *) data;
|
|
} else {
|
|
throw_(value_error, "Value is not a boolean");
|
|
value_t temp(*this);
|
|
temp.in_place_cast(BOOLEAN);
|
|
return *(bool *) temp.data;
|
|
}
|
|
}
|
|
|
|
long& value_t::integer()
|
|
{
|
|
if (type == INTEGER) {
|
|
return *(long *) data;
|
|
} else {
|
|
throw_(value_error, "Value is not an integer");
|
|
value_t temp(*this);
|
|
temp.in_place_cast(INTEGER);
|
|
return *(long *) temp.data;
|
|
}
|
|
}
|
|
|
|
moment_t& value_t::datetime()
|
|
{
|
|
if (type == DATETIME) {
|
|
return *(moment_t *) data;
|
|
} else {
|
|
throw_(value_error, "Value is not a date/time");
|
|
value_t temp(*this);
|
|
temp.in_place_cast(DATETIME);
|
|
return *(moment_t *) temp.data;
|
|
}
|
|
}
|
|
|
|
amount_t& value_t::amount()
|
|
{
|
|
if (type == AMOUNT) {
|
|
return *(amount_t *) data;
|
|
} else {
|
|
throw_(value_error, "Value is not an amount");
|
|
value_t temp(*this);
|
|
temp.in_place_cast(AMOUNT);
|
|
return *(amount_t *) temp.data;
|
|
}
|
|
}
|
|
|
|
balance_t& value_t::balance()
|
|
{
|
|
if (type == BALANCE) {
|
|
return *(balance_t *) data;
|
|
} else {
|
|
throw_(value_error, "Value is not a balance");
|
|
value_t temp(*this);
|
|
temp.in_place_cast(BALANCE);
|
|
return *(balance_t *) temp.data;
|
|
}
|
|
}
|
|
|
|
balance_pair_t& value_t::balance_pair()
|
|
{
|
|
if (type == BALANCE_PAIR) {
|
|
return *(balance_pair_t *) data;
|
|
} else {
|
|
throw_(value_error, "Value is not a balance pair");
|
|
value_t temp(*this);
|
|
temp.in_place_cast(BALANCE_PAIR);
|
|
return *(balance_pair_t *) temp.data;
|
|
}
|
|
}
|
|
|
|
string& value_t::string_value()
|
|
{
|
|
if (type == STRING) {
|
|
return **(string **) data;
|
|
} else {
|
|
throw_(value_error, "Value is not a string");
|
|
#if 0
|
|
std::ostringstream out;
|
|
out << *this;
|
|
return out.str();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
xml::node_t *& value_t::xml_node()
|
|
{
|
|
if (type == XML_NODE)
|
|
return *(xml::node_t **) data;
|
|
else
|
|
throw_(value_error, "Value is not an XML node");
|
|
}
|
|
|
|
void *& value_t::pointer()
|
|
{
|
|
if (type == POINTER)
|
|
return *(void **) data;
|
|
else
|
|
throw_(value_error, "Value is not a pointer");
|
|
}
|
|
|
|
value_t::sequence_t *& value_t::sequence()
|
|
{
|
|
if (type == SEQUENCE)
|
|
return *(sequence_t **) data;
|
|
else
|
|
throw_(value_error, "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:
|
|
checked_delete(*(string **) data);
|
|
break;
|
|
case SEQUENCE:
|
|
checked_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_error, "Cannot add a boolean to a value");
|
|
else if (val.type == DATETIME)
|
|
throw_(value_error, "Cannot add a date/time to a value");
|
|
else if (val.type == POINTER)
|
|
throw_(value_error, "Cannot add a pointer to a value");
|
|
else if (val.type == SEQUENCE)
|
|
throw_(value_error, "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_error, "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_error, "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_error, "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_error, "Cannot add a string to an amount");
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case BALANCE:
|
|
switch (val.type) {
|
|
case INTEGER:
|
|
*((balance_t *) data) += amount_t(*((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_error, "Cannot add a string to an balance");
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case BALANCE_PAIR:
|
|
switch (val.type) {
|
|
case INTEGER:
|
|
*((balance_pair_t *) data) += amount_t(*((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_error, "Cannot add a string to an balance pair");
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case STRING:
|
|
switch (val.type) {
|
|
case INTEGER:
|
|
throw_(value_error, "Cannot add an integer to a string");
|
|
case AMOUNT:
|
|
throw_(value_error, "Cannot add an amount to a string");
|
|
case BALANCE:
|
|
throw_(value_error, "Cannot add a balance to a string");
|
|
case BALANCE_PAIR:
|
|
throw_(value_error, "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_error, "Cannot add a value to an XML node");
|
|
|
|
case POINTER:
|
|
throw_(value_error, "Cannot add a value to a pointer");
|
|
|
|
case SEQUENCE:
|
|
throw_(value_error, "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_error, "Cannot subtract a boolean from a value");
|
|
else if (val.type == DATETIME && type != DATETIME)
|
|
throw_(value_error, "Cannot subtract a date/time from a value");
|
|
else if (val.type == STRING)
|
|
throw_(value_error, "Cannot subtract a string from a value");
|
|
else if (val.type == POINTER)
|
|
throw_(value_error, "Cannot subtract a pointer from a value");
|
|
else if (val.type == SEQUENCE)
|
|
throw_(value_error, "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_error, "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) -= amount_t(*((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) -= amount_t(*((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_error, "Cannot subtract a value from a string");
|
|
case XML_NODE:
|
|
throw_(value_error, "Cannot subtract a value from an XML node");
|
|
case POINTER:
|
|
throw_(value_error, "Cannot subtract a value from a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "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_error, "Cannot multiply a value by a boolean");
|
|
else if (val.type == DATETIME)
|
|
throw_(value_error, "Cannot multiply a value by a date/time");
|
|
else if (val.type == STRING)
|
|
throw_(value_error, "Cannot multiply a value by a string");
|
|
else if (val.type == POINTER)
|
|
throw_(value_error, "Cannot multiply a value by a pointer");
|
|
else if (val.type == SEQUENCE)
|
|
throw_(value_error, "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_error, "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) *= amount_t(*((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_error, "Cannot multiply a string by a balance");
|
|
case BALANCE_PAIR:
|
|
throw_(value_error, "Cannot multiply a string by a balance pair");
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case XML_NODE:
|
|
throw_(value_error, "Cannot multiply an XML node by a value");
|
|
case POINTER:
|
|
throw_(value_error, "Cannot multiply a pointer by a value");
|
|
case SEQUENCE:
|
|
throw_(value_error, "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_error, "Cannot divide a boolean by a value");
|
|
else if (val.type == DATETIME)
|
|
throw_(value_error, "Cannot divide a date/time by a value");
|
|
else if (val.type == STRING)
|
|
throw_(value_error, "Cannot divide a string by a value");
|
|
else if (val.type == POINTER)
|
|
throw_(value_error, "Cannot divide a pointer by a value");
|
|
else if (val.type == SEQUENCE)
|
|
throw_(value_error, "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_error, "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) /= amount_t(*((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_error, "Cannot divide a value from a string");
|
|
case XML_NODE:
|
|
throw_(value_error, "Cannot divide a value from an XML node");
|
|
case POINTER:
|
|
throw_(value_error, "Cannot divide a value from a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "Cannot divide a value from a sequence");
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
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().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;
|
|
}
|
|
|
|
#if 0
|
|
template <>
|
|
value_t::operator long() const
|
|
{
|
|
switch (type) {
|
|
case BOOLEAN:
|
|
throw_(value_error, "Cannot convert a boolean to an integer");
|
|
case INTEGER:
|
|
return *((long *) data);
|
|
case DATETIME:
|
|
throw_(value_error, "Cannot convert a date/time to an integer");
|
|
case AMOUNT:
|
|
return *((amount_t *) data);
|
|
case BALANCE:
|
|
throw_(value_error, "Cannot convert a balance to an integer");
|
|
case BALANCE_PAIR:
|
|
throw_(value_error, "Cannot convert a balance pair to an integer");
|
|
case STRING:
|
|
throw_(value_error, "Cannot convert a string to an integer");
|
|
case XML_NODE:
|
|
return (*(xml::node_t **) data)->to_value().to_integer();
|
|
case POINTER:
|
|
throw_(value_error, "Cannot convert a pointer to an integer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "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_error, "Cannot convert a boolean to a date/time");
|
|
case INTEGER:
|
|
throw_(value_error, "Cannot convert an integer to a date/time");
|
|
case DATETIME:
|
|
return *((moment_t *) data);
|
|
case AMOUNT:
|
|
throw_(value_error, "Cannot convert an amount to a date/time");
|
|
case BALANCE:
|
|
throw_(value_error, "Cannot convert a balance to a date/time");
|
|
case BALANCE_PAIR:
|
|
throw_(value_error, "Cannot convert a balance pair to a date/time");
|
|
case STRING:
|
|
throw_(value_error, "Cannot convert a string to a date/time");
|
|
case XML_NODE:
|
|
return (*(xml::node_t **) data)->to_value().to_datetime();
|
|
case POINTER:
|
|
throw_(value_error, "Cannot convert a pointer to a date/time");
|
|
case SEQUENCE:
|
|
throw_(value_error, "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_error, "Cannot convert a boolean to a double");
|
|
case INTEGER:
|
|
return *((long *) data);
|
|
case DATETIME:
|
|
throw_(value_error, "Cannot convert a date/time to a double");
|
|
case AMOUNT:
|
|
return *((amount_t *) data);
|
|
case BALANCE:
|
|
throw_(value_error, "Cannot convert a balance to a double");
|
|
case BALANCE_PAIR:
|
|
throw_(value_error, "Cannot convert a balance pair to a double");
|
|
case STRING:
|
|
throw_(value_error, "Cannot convert a string to a double");
|
|
case XML_NODE:
|
|
return (*(xml::node_t **) data)->to_value().to_amount().number();
|
|
case POINTER:
|
|
throw_(value_error, "Cannot convert a pointer to a double");
|
|
case SEQUENCE:
|
|
throw_(value_error, "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_error, "Cannot convert a pointer to a string");
|
|
case SEQUENCE:
|
|
throw_(value_error, "Cannot convert a sequence to a string");
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
assert(0);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
template <typename T>
|
|
inline int compare_bool(const T& left, const T& right) {
|
|
return (! left && right ? -1 : (left && ! right ? 1 : 0));
|
|
}
|
|
|
|
// jww (2007-05-01): This is going to be slow as hell for two
|
|
// balance_t objects
|
|
template <typename T>
|
|
inline int compare_equality(const T& left, const T& right) {
|
|
return (left < right ? -1 : (left > right ? 1 : 0));
|
|
}
|
|
|
|
int value_t::compare(const value_t& val) const
|
|
{
|
|
if (val.type == XML_NODE)
|
|
return compare((*(xml::node_t **) data)->to_value());
|
|
|
|
switch (type) {
|
|
case BOOLEAN:
|
|
switch (val.type) {
|
|
case BOOLEAN:
|
|
return compare_bool(*((bool *) data), *((bool *) val.data));
|
|
|
|
case INTEGER:
|
|
return compare_bool(*((bool *) data), bool(*((long *) val.data)));
|
|
|
|
case DATETIME:
|
|
throw_(value_error, "Cannot compare a boolean to a date/time");
|
|
|
|
case AMOUNT:
|
|
return compare_bool(*((bool *) data), bool(*((amount_t *) val.data)));
|
|
|
|
case BALANCE:
|
|
return compare_bool(*((bool *) data), bool(*((balance_t *) val.data)));
|
|
|
|
case BALANCE_PAIR:
|
|
return compare_bool(*((bool *) data), bool(*((balance_pair_t *) val.data)));
|
|
|
|
case STRING:
|
|
throw_(value_error, "Cannot compare a boolean to a string");
|
|
case POINTER:
|
|
throw_(value_error, "Cannot compare a boolean to a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "Cannot compare a boolean to a sequence");
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case INTEGER:
|
|
switch (val.type) {
|
|
case BOOLEAN:
|
|
return *((long *) data) - ((long) *((bool *) val.data));
|
|
|
|
case INTEGER:
|
|
return *((long *) data) - *((long *) val.data);
|
|
|
|
case DATETIME:
|
|
throw_(value_error, "Cannot compare an integer to a date/time");
|
|
|
|
case AMOUNT:
|
|
return amount_t(*((long *) data)).compare(*((amount_t *) val.data));
|
|
|
|
case BALANCE:
|
|
return compare_equality(balance_t(*((long *) data)),
|
|
*((balance_t *) val.data));
|
|
|
|
case BALANCE_PAIR:
|
|
return compare_equality(balance_pair_t(*((long *) data)),
|
|
*((balance_pair_t *) val.data));
|
|
|
|
case STRING:
|
|
throw_(value_error, "Cannot compare an integer to a string");
|
|
case POINTER:
|
|
throw_(value_error, "Cannot compare an integer to a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "Cannot compare an integer to a sequence");
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case DATETIME:
|
|
switch (val.type) {
|
|
case BOOLEAN:
|
|
throw_(value_error, "Cannot compare a date/time to a boolean");
|
|
case INTEGER:
|
|
throw_(value_error, "Cannot compare a date/time to an integer");
|
|
|
|
case DATETIME:
|
|
return compare_equality(*((moment_t *) data), *((moment_t *) val.data));
|
|
|
|
case AMOUNT:
|
|
throw_(value_error, "Cannot compare a date/time to an amount");
|
|
case BALANCE:
|
|
throw_(value_error, "Cannot compare a date/time to a balance");
|
|
case BALANCE_PAIR:
|
|
throw_(value_error, "Cannot compare a date/time to a balance pair");
|
|
case STRING:
|
|
throw_(value_error, "Cannot compare a date/time to a string");
|
|
case POINTER:
|
|
throw_(value_error, "Cannot compare a date/time to a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "Cannot compare a date/time to a sequence");
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case AMOUNT:
|
|
switch (val.type) {
|
|
case BOOLEAN:
|
|
throw_(value_error, "Cannot compare an amount to a boolean");
|
|
|
|
case INTEGER:
|
|
return ((amount_t *) data)->compare(*((long *) val.data));
|
|
|
|
case DATETIME:
|
|
throw_(value_error, "Cannot compare an amount to a date/time");
|
|
|
|
case AMOUNT:
|
|
return ((amount_t *) data)->compare(*((amount_t *) val.data));
|
|
|
|
case BALANCE:
|
|
return compare_equality(balance_t(*((amount_t *) data)),
|
|
*((balance_t *) val.data));
|
|
|
|
case BALANCE_PAIR:
|
|
return compare_equality(balance_pair_t(*((amount_t *) data)),
|
|
*((balance_pair_t *) val.data));
|
|
|
|
case STRING:
|
|
throw_(value_error, "Cannot compare an amount to a string");
|
|
case POINTER:
|
|
throw_(value_error, "Cannot compare an amount to a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "Cannot compare an amount to a sequence");
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case BALANCE:
|
|
switch (val.type) {
|
|
case BOOLEAN:
|
|
throw_(value_error, "Cannot compare a balance to a boolean");
|
|
|
|
case INTEGER:
|
|
return compare_equality(*(balance_t *) data,
|
|
balance_t(*((long *) val.data)));
|
|
|
|
case DATETIME:
|
|
throw_(value_error, "Cannot compare a balance to a date/time");
|
|
|
|
case AMOUNT:
|
|
return compare_equality(*(balance_t *) data,
|
|
balance_t(*((amount_t *) val.data)));
|
|
|
|
case BALANCE:
|
|
return compare_equality(*(balance_t *) data, *((balance_t *) val.data));
|
|
|
|
case BALANCE_PAIR:
|
|
return compare_equality(balance_pair_t(*((balance_t *) data)),
|
|
*(balance_pair_t *) val.data);
|
|
|
|
case STRING:
|
|
throw_(value_error, "Cannot compare a balance to a string");
|
|
case POINTER:
|
|
throw_(value_error, "Cannot compare a balance to a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "Cannot compare a balance to a sequence");
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case BALANCE_PAIR:
|
|
switch (val.type) {
|
|
case BOOLEAN:
|
|
throw_(value_error, "Cannot compare a balance pair to a boolean");
|
|
|
|
case INTEGER:
|
|
return compare_equality(*(balance_pair_t *) data,
|
|
balance_pair_t(amount_t(*((long *) val.data))));
|
|
|
|
case DATETIME:
|
|
throw_(value_error, "Cannot compare a balance pair to a date/time");
|
|
|
|
case AMOUNT:
|
|
return compare_equality(*(balance_pair_t *) data,
|
|
balance_pair_t(*((amount_t *) val.data)));
|
|
|
|
case BALANCE:
|
|
return compare_equality(*(balance_pair_t *) data,
|
|
balance_pair_t(*((balance_t *) val.data)));
|
|
|
|
case BALANCE_PAIR:
|
|
return compare_equality(*(balance_pair_t *) data,
|
|
*((balance_pair_t *) val.data));
|
|
|
|
case STRING:
|
|
throw_(value_error, "Cannot compare a balance pair to a string");
|
|
case POINTER:
|
|
throw_(value_error, "Cannot compare a balance pair to a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "Cannot compare a balance pair to a sequence");
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case STRING:
|
|
switch (val.type) {
|
|
case BOOLEAN:
|
|
throw_(value_error, "Cannot compare a string to a boolean");
|
|
case INTEGER:
|
|
throw_(value_error, "Cannot compare a string to an integer");
|
|
case DATETIME:
|
|
throw_(value_error, "Cannot compare a string to a date/time");
|
|
case AMOUNT:
|
|
throw_(value_error, "Cannot compare a string to an amount");
|
|
case BALANCE:
|
|
throw_(value_error, "Cannot compare a string to a balance");
|
|
case BALANCE_PAIR:
|
|
throw_(value_error, "Cannot compare a string to a balance pair");
|
|
|
|
case STRING:
|
|
return (**((string **) data)).compare(**((string **) val.data));
|
|
|
|
case POINTER:
|
|
throw_(value_error, "Cannot compare a string to a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "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().compare(*this);
|
|
case INTEGER:
|
|
return (*(xml::node_t **) data)->to_value().compare(*this);
|
|
case DATETIME:
|
|
return (*(xml::node_t **) data)->to_value().compare(*this);
|
|
case AMOUNT:
|
|
return (*(xml::node_t **) data)->to_value().compare(*this);
|
|
case BALANCE:
|
|
return (*(xml::node_t **) data)->to_value().compare(*this);
|
|
case BALANCE_PAIR:
|
|
return (*(xml::node_t **) data)->to_value().compare(*this);
|
|
case STRING:
|
|
return (*(xml::node_t **) data)->to_value().compare(*this);
|
|
|
|
case POINTER:
|
|
throw_(value_error, "Cannot compare an XML node to a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "Cannot compare an XML node to a sequence");
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case POINTER:
|
|
switch (val.type) {
|
|
case BOOLEAN:
|
|
throw_(value_error, "Cannot compare a pointer to a boolean");
|
|
case INTEGER:
|
|
throw_(value_error, "Cannot compare a pointer to an integer");
|
|
case DATETIME:
|
|
throw_(value_error, "Cannot compare a pointer to a date/time");
|
|
case AMOUNT:
|
|
throw_(value_error, "Cannot compare a pointer to an amount");
|
|
case BALANCE:
|
|
throw_(value_error, "Cannot compare a pointer to a balance");
|
|
case BALANCE_PAIR:
|
|
throw_(value_error, "Cannot compare a pointer to a balance pair");
|
|
case STRING:
|
|
throw_(value_error, "Cannot compare a pointer to a string node");
|
|
case POINTER:
|
|
throw_(value_error, "Cannot compare two pointers");
|
|
case SEQUENCE:
|
|
throw_(value_error, "Cannot compare a pointer to a sequence");
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case SEQUENCE:
|
|
throw_(value_error, "Cannot compare a value to a sequence");
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
#if 0
|
|
DEF_VALUE_CMP_OP(==)
|
|
DEF_VALUE_CMP_OP(<)
|
|
DEF_VALUE_CMP_OP(<=)
|
|
DEF_VALUE_CMP_OP(>)
|
|
DEF_VALUE_CMP_OP(>=)
|
|
#endif
|
|
|
|
void value_t::in_place_cast(type_t cast_type)
|
|
{
|
|
switch (type) {
|
|
case BOOLEAN:
|
|
switch (cast_type) {
|
|
case BOOLEAN:
|
|
break;
|
|
case INTEGER:
|
|
throw_(value_error, "Cannot convert a boolean to an integer");
|
|
case DATETIME:
|
|
throw_(value_error, "Cannot convert a boolean to a date/time");
|
|
case AMOUNT:
|
|
throw_(value_error, "Cannot convert a boolean to an amount");
|
|
case BALANCE:
|
|
throw_(value_error, "Cannot convert a boolean to a balance");
|
|
case BALANCE_PAIR:
|
|
throw_(value_error, "Cannot convert a boolean to a balance pair");
|
|
case STRING:
|
|
*(string **) data = new string(*((bool *) data) ? "true" : "false");
|
|
break;
|
|
case XML_NODE:
|
|
throw_(value_error, "Cannot convert a boolean to an XML node");
|
|
case POINTER:
|
|
throw_(value_error, "Cannot convert a boolean to a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "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_error, "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_error, "Cannot convert an integer to an XML node");
|
|
case POINTER:
|
|
throw_(value_error, "Cannot convert an integer to a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "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_error, "Cannot convert a date/time to an integer");
|
|
case DATETIME:
|
|
break;
|
|
case AMOUNT:
|
|
throw_(value_error, "Cannot convert a date/time to an amount");
|
|
case BALANCE:
|
|
throw_(value_error, "Cannot convert a date/time to a balance");
|
|
case BALANCE_PAIR:
|
|
throw_(value_error, "Cannot convert a date/time to a balance pair");
|
|
case STRING:
|
|
throw_(value_error, "Cannot convert a date/time to a string");
|
|
case XML_NODE:
|
|
throw_(value_error, "Cannot convert a date/time to an XML node");
|
|
case POINTER:
|
|
throw_(value_error, "Cannot convert a date/time to a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "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_error, "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_error, "Cannot convert an amount to an XML node");
|
|
case POINTER:
|
|
throw_(value_error, "Cannot convert an amount to a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "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_error, "Cannot convert a balance to an integer");
|
|
case DATETIME:
|
|
throw_(value_error, "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_error, "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_error, "Cannot convert a balance to a string");
|
|
case XML_NODE:
|
|
throw_(value_error, "Cannot convert a balance to an XML node");
|
|
case POINTER:
|
|
throw_(value_error, "Cannot convert a balance to a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "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_error, "Cannot convert a balance pair to an integer");
|
|
case DATETIME:
|
|
throw_(value_error, "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_error, "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_error, "Cannot convert a balance pair to a string");
|
|
case XML_NODE:
|
|
throw_(value_error, "Cannot convert a balance pair to an XML node");
|
|
case POINTER:
|
|
throw_(value_error, "Cannot convert a balance pair to a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "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_error, "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 = lexical_cast<long>((*(string **) data)->c_str());
|
|
destroy();
|
|
*(long *) data = temp;
|
|
} else {
|
|
throw_(value_error, "Cannot convert string to an integer");
|
|
}
|
|
break;
|
|
}
|
|
|
|
case DATETIME:
|
|
throw_(value_error, "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_error, "Cannot convert a string to a balance");
|
|
case BALANCE_PAIR:
|
|
throw_(value_error, "Cannot convert a string to a balance pair");
|
|
case STRING:
|
|
break;
|
|
case XML_NODE:
|
|
throw_(value_error, "Cannot convert a string to an XML node");
|
|
case POINTER:
|
|
throw_(value_error, "Cannot convert a string to a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "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_error, "Cannot convert an XML node to a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "Cannot convert an XML node to a sequence");
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case POINTER:
|
|
switch (cast_type) {
|
|
case BOOLEAN:
|
|
throw_(value_error, "Cannot convert a pointer to a boolean");
|
|
case INTEGER:
|
|
throw_(value_error, "Cannot convert a pointer to an integer");
|
|
case DATETIME:
|
|
throw_(value_error, "Cannot convert a pointer to a date/time");
|
|
case AMOUNT:
|
|
throw_(value_error, "Cannot convert a pointer to an amount");
|
|
case BALANCE:
|
|
throw_(value_error, "Cannot convert a pointer to a balance");
|
|
case BALANCE_PAIR:
|
|
throw_(value_error, "Cannot convert a pointer to a balance pair");
|
|
case STRING:
|
|
throw_(value_error, "Cannot convert a pointer to a string");
|
|
case XML_NODE:
|
|
throw_(value_error, "Cannot convert a pointer to an XML node");
|
|
case POINTER:
|
|
break;
|
|
case SEQUENCE:
|
|
throw_(value_error, "Cannot convert a pointer to a sequence");
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case SEQUENCE:
|
|
switch (cast_type) {
|
|
case BOOLEAN:
|
|
throw_(value_error, "Cannot convert a sequence to a boolean");
|
|
case INTEGER:
|
|
throw_(value_error, "Cannot convert a sequence to an integer");
|
|
case DATETIME:
|
|
throw_(value_error, "Cannot convert a sequence to a date/time");
|
|
case AMOUNT:
|
|
throw_(value_error, "Cannot convert a sequence to an amount");
|
|
case BALANCE:
|
|
throw_(value_error, "Cannot convert a sequence to a balance");
|
|
case BALANCE_PAIR:
|
|
throw_(value_error, "Cannot convert a sequence to a balance pair");
|
|
case STRING:
|
|
throw_(value_error, "Cannot convert a sequence to a string");
|
|
case XML_NODE:
|
|
throw_(value_error, "Cannot compare a sequence to an XML node");
|
|
case POINTER:
|
|
throw_(value_error, "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_error, "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_error, "Cannot negate a string");
|
|
case XML_NODE:
|
|
*this = (*(xml::node_t **) data)->to_value();
|
|
in_place_negate();
|
|
break;
|
|
case POINTER:
|
|
throw_(value_error, "Cannot negate a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "Cannot negate a sequence");
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool value_t::realzero() const
|
|
{
|
|
switch (type) {
|
|
case BOOLEAN:
|
|
return ! *((bool *) data);
|
|
case INTEGER:
|
|
return *((long *) data) == 0;
|
|
case DATETIME:
|
|
return ! is_valid_moment(*((moment_t *) data));
|
|
case AMOUNT:
|
|
return ((amount_t *) data)->realzero();
|
|
case BALANCE:
|
|
return ((balance_t *) data)->realzero();
|
|
case BALANCE_PAIR:
|
|
return ((balance_pair_t *) data)->realzero();
|
|
case STRING:
|
|
return ((string *) data)->empty();
|
|
case XML_NODE:
|
|
case POINTER:
|
|
case SEQUENCE:
|
|
return *(void **) data == NULL;
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
assert(0);
|
|
return 0;
|
|
}
|
|
|
|
value_t value_t::value(const optional<moment_t>& moment) const
|
|
{
|
|
switch (type) {
|
|
case BOOLEAN:
|
|
throw_(value_error, "Cannot find the value of a boolean");
|
|
case DATETIME:
|
|
throw_(value_error, "Cannot find the value of a date/time");
|
|
case INTEGER:
|
|
return *this;
|
|
|
|
case AMOUNT: {
|
|
if (optional<amount_t> val = ((amount_t *) data)->value(moment))
|
|
return *val;
|
|
return false;
|
|
}
|
|
case BALANCE: {
|
|
if (optional<balance_t> bal = ((balance_t *) data)->value(moment))
|
|
return *bal;
|
|
return false;
|
|
}
|
|
case BALANCE_PAIR: {
|
|
if (optional<balance_t> bal =
|
|
((balance_pair_t *) data)->quantity.value(moment))
|
|
return *bal;
|
|
return false;
|
|
}
|
|
|
|
case STRING:
|
|
throw_(value_error, "Cannot find the value of a string");
|
|
|
|
case XML_NODE:
|
|
return (*(xml::node_t **) data)->to_value().value(moment);
|
|
|
|
case POINTER:
|
|
throw_(value_error, "Cannot find the value of a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "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_error, "Cannot reduce a string");
|
|
case XML_NODE:
|
|
*this = (*(xml::node_t **) data)->to_value();
|
|
in_place_reduce(); // recurse
|
|
break;
|
|
case POINTER:
|
|
throw_(value_error, "Cannot reduce a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "Cannot reduce a sequence");
|
|
}
|
|
}
|
|
|
|
value_t value_t::round() const
|
|
{
|
|
switch (type) {
|
|
case BOOLEAN:
|
|
throw_(value_error, "Cannot round a boolean");
|
|
case DATETIME:
|
|
throw_(value_error, "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_error, "Cannot round a string");
|
|
case XML_NODE:
|
|
return (*(xml::node_t **) data)->to_value().round();
|
|
case POINTER:
|
|
throw_(value_error, "Cannot round a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "Cannot round a sequence");
|
|
}
|
|
assert(0);
|
|
return value_t();
|
|
}
|
|
|
|
value_t value_t::unround() const
|
|
{
|
|
switch (type) {
|
|
case BOOLEAN:
|
|
throw_(value_error, "Cannot un-round a boolean");
|
|
case DATETIME:
|
|
throw_(value_error, "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_error, "Cannot un-round a string");
|
|
case XML_NODE:
|
|
return (*(xml::node_t **) data)->to_value().unround();
|
|
case POINTER:
|
|
throw_(value_error, "Cannot un-round a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "Cannot un-round a sequence");
|
|
}
|
|
assert(0);
|
|
return value_t();
|
|
}
|
|
|
|
value_t value_t::annotated_price() const
|
|
{
|
|
switch (type) {
|
|
case BOOLEAN:
|
|
throw_(value_error, "Cannot find the annotated price of a boolean");
|
|
case INTEGER:
|
|
return *this;
|
|
case DATETIME:
|
|
throw_(value_error, "Cannot find the annotated price of a date/time");
|
|
|
|
case AMOUNT: {
|
|
optional<amount_t> temp = ((amount_t *) data)->annotation_details().price;
|
|
if (! temp)
|
|
return false;
|
|
return *temp;
|
|
}
|
|
|
|
case BALANCE:
|
|
throw_(value_error, "Cannot find the annotated price of a balance");
|
|
case BALANCE_PAIR:
|
|
throw_(value_error, "Cannot find the annotated price of a balance pair");
|
|
case STRING:
|
|
throw_(value_error, "Cannot find the annotated price of a string");
|
|
|
|
case XML_NODE:
|
|
return (*(xml::node_t **) data)->to_value().annotated_price();
|
|
|
|
case POINTER:
|
|
throw_(value_error, "Cannot find the annotated price of a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "Cannot find the annotated price of a sequence");
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
assert(0);
|
|
return value_t();
|
|
}
|
|
|
|
value_t value_t::annotated_date() const
|
|
{
|
|
switch (type) {
|
|
case BOOLEAN:
|
|
throw_(value_error, "Cannot find the annotated date of a boolean");
|
|
case INTEGER:
|
|
throw_(value_error, "Cannot find the annotated date of an integer");
|
|
|
|
case DATETIME:
|
|
return *this;
|
|
|
|
case AMOUNT: {
|
|
optional<moment_t> temp = ((amount_t *) data)->annotation_details().date;
|
|
if (! temp)
|
|
return false;
|
|
return *temp;
|
|
}
|
|
|
|
case BALANCE:
|
|
throw_(value_error, "Cannot find the annotated date of a balance");
|
|
case BALANCE_PAIR:
|
|
throw_(value_error, "Cannot find the annotated date of a balance pair");
|
|
case STRING:
|
|
throw_(value_error, "Cannot find the annotated date of a string");
|
|
|
|
case XML_NODE:
|
|
return (*(xml::node_t **) data)->to_value().annotated_date();
|
|
|
|
case POINTER:
|
|
throw_(value_error, "Cannot find the annotated date of a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "Cannot find the annotated date of a sequence");
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
assert(0);
|
|
return value_t();
|
|
}
|
|
|
|
value_t value_t::annotated_tag() const
|
|
{
|
|
switch (type) {
|
|
case BOOLEAN:
|
|
throw_(value_error, "Cannot find the annotated tag of a boolean");
|
|
case INTEGER:
|
|
throw_(value_error, "Cannot find the annotated tag of an integer");
|
|
|
|
case DATETIME:
|
|
return *this;
|
|
|
|
case AMOUNT: {
|
|
optional<string> temp = ((amount_t *) data)->annotation_details().tag;
|
|
if (! temp)
|
|
return false;
|
|
return *temp;
|
|
}
|
|
|
|
case BALANCE:
|
|
throw_(value_error, "Cannot find the annotated tag of a balance");
|
|
case BALANCE_PAIR:
|
|
throw_(value_error, "Cannot find the annotated tag of a balance pair");
|
|
case STRING:
|
|
throw_(value_error, "Cannot find the annotated tag of a string");
|
|
|
|
case XML_NODE:
|
|
return (*(xml::node_t **) data)->to_value().annotated_tag();
|
|
|
|
case POINTER:
|
|
throw_(value_error, "Cannot find the annotated tag of a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "Cannot find the annotated tag 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_error, "Cannot find the cost of a boolean");
|
|
case INTEGER:
|
|
case AMOUNT:
|
|
case BALANCE:
|
|
return *this;
|
|
case DATETIME:
|
|
throw_(value_error, "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_error, "Cannot find the cost of a string");
|
|
case XML_NODE:
|
|
return (*(xml::node_t **) data)->to_value().cost();
|
|
case POINTER:
|
|
throw_(value_error, "Cannot find the cost of a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "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 optional<amount_t>& tcost)
|
|
{
|
|
switch (type) {
|
|
case BOOLEAN:
|
|
throw_(value_error, "Cannot add an amount to a boolean");
|
|
case DATETIME:
|
|
throw_(value_error, "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_error, "Cannot add an amount to a string");
|
|
case XML_NODE:
|
|
throw_(value_error, "Cannot add an amount to an XML node");
|
|
case POINTER:
|
|
throw_(value_error, "Cannot add an amount to a pointer");
|
|
case SEQUENCE:
|
|
throw_(value_error, "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_error, "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_error, "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()
|
|
{
|
|
checked_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
|