summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2007-05-16 05:37:26 +0000
committerJohn Wiegley <johnw@newartisans.com>2008-04-13 03:38:52 -0400
commit52822604713b73160ac497bc170eb45d9a594306 (patch)
tree867027ab9186c04e7ecb2f101247f16307116e86
parentd89f6e1c447fc5e7fcd0d6e5a236298323f9596e (diff)
downloadfork-ledger-52822604713b73160ac497bc170eb45d9a594306.tar.gz
fork-ledger-52822604713b73160ac497bc170eb45d9a594306.tar.bz2
fork-ledger-52822604713b73160ac497bc170eb45d9a594306.zip
Modified value_t to use copy-on-write semantics.
-rw-r--r--src/journal.cc8
-rw-r--r--src/pyinterp.cc8
-rw-r--r--src/session.cc2
-rw-r--r--src/value.cc817
-rw-r--r--src/value.h407
-rw-r--r--src/xpath.cc34
-rw-r--r--src/xpath.h28
7 files changed, 690 insertions, 614 deletions
diff --git a/src/journal.cc b/src/journal.cc
index 9ff42832..2f501aff 100644
--- a/src/journal.cc
+++ b/src/journal.cc
@@ -153,7 +153,7 @@ bool entry_base_t::finalize()
// account if one has been set.
if (journal && journal->basket && transactions.size() == 1) {
- assert(balance.type < value_t::BALANCE);
+ assert(balance.is_type(value_t::AMOUNT));
transaction_t * nxact = new transaction_t(journal->basket);
// The amount doesn't need to be set because the code below will
// balance this transaction against the other.
@@ -166,7 +166,7 @@ bool entry_base_t::finalize()
// determine its price by dividing the unit count into the value of
// the balance. This is done for the last eligible commodity.
- if (! saw_null && balance && balance.type == value_t::BALANCE &&
+ if (! saw_null && balance && balance.is_type(value_t::BALANCE) &&
balance.as_balance().amounts.size() == 2) {
transactions_list::const_iterator x = transactions.begin();
assert((*x)->amount);
@@ -227,8 +227,8 @@ bool entry_base_t::finalize()
// commodities are involved, multiple transactions will be
// generated to balance them all.
- balance_t * bal = NULL;
- switch (balance.type) {
+ const balance_t * bal = NULL;
+ switch (balance.type()) {
case value_t::BALANCE_PAIR:
bal = &balance.as_balance_pair().quantity;
// fall through...
diff --git a/src/pyinterp.cc b/src/pyinterp.cc
index fbc2eab4..4a2f1e75 100644
--- a/src/pyinterp.cc
+++ b/src/pyinterp.cc
@@ -180,10 +180,10 @@ void python_interpreter_t::functor_t::operator()(value_t& result,
if (! PyCallable_Check(func.ptr())) {
result = static_cast<const value_t&>(extract<value_t>(func.ptr()));
} else {
- assert(locals->args.type == value_t::SEQUENCE);
+ assert(locals->args.is_type(value_t::SEQUENCE));
if (locals->args.as_sequence().size() > 0) {
list arglist;
- for (value_t::sequence_t::iterator
+ for (value_t::sequence_t::const_iterator
i = locals->args.as_sequence().begin();
i != locals->args.as_sequence().end();
i++)
@@ -218,10 +218,10 @@ void python_interpreter_t::lambda_t::operator()(value_t& result,
xml::xpath_t::scope_t * locals)
{
try {
- assert(locals->args.type == value_t::SEQUENCE);
+ assert(locals->args.is_type(value_t::SEQUENCE));
assert(locals->args.as_sequence().size() == 1);
value_t item = locals->args[0];
- assert(item.type == value_t::POINTER);
+ assert(item.is_type(value_t::POINTER));
result = call<value_t>(func.ptr(), item.as_xml_node());
}
catch (const error_already_set&) {
diff --git a/src/session.cc b/src/session.cc
index 65b9ada5..4bb88e4e 100644
--- a/src/session.cc
+++ b/src/session.cc
@@ -253,12 +253,14 @@ xml::xpath_t::ptr_op_t session_t::lookup(const string& name)
static void initialize()
{
amount_t::initialize();
+ value_t::initialize();
xml::xpath_t::initialize();
}
static void shutdown()
{
xml::xpath_t::shutdown();
+ value_t::shutdown();
amount_t::shutdown();
}
diff --git a/src/value.cc b/src/value.cc
index b3578ae9..4089e0c3 100644
--- a/src/value.cc
+++ b/src/value.cc
@@ -34,9 +34,162 @@
namespace ledger {
+intrusive_ptr<value_t::storage_t> value_t::true_value;
+intrusive_ptr<value_t::storage_t> value_t::false_value;
+
+void value_t::storage_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:
+ ((string *)data)->~string();
+ break;
+ case SEQUENCE:
+ ((sequence_t *)data)->~sequence_t();
+ break;
+
+ default:
+ break;
+ }
+ type = VOID;
+}
+
+void value_t::initialize()
+{
+ true_value = new storage_t;
+ true_value->type = BOOLEAN;
+ *(bool *) true_value->data = true;
+
+ false_value = new storage_t;
+ false_value->type = BOOLEAN;
+ *(bool *) false_value->data = false;
+}
+
+void value_t::shutdown()
+{
+ true_value = intrusive_ptr<storage_t>();
+ false_value = intrusive_ptr<storage_t>();
+}
+
+value_t& value_t::operator=(const value_t& val)
+{
+ if (this == &val || storage == val.storage)
+ return *this;
+
+ if (type() == val.type())
+ switch (type()) {
+ case BOOLEAN:
+ as_boolean_lval() = val.as_boolean();
+ return *this;
+ case INTEGER:
+ as_long_lval() = val.as_long();
+ return *this;
+ case DATETIME:
+ as_datetime_lval() = val.as_datetime();
+ return *this;
+ case AMOUNT:
+ as_amount_lval() = val.as_amount();
+ return *this;
+ case BALANCE:
+ as_balance_lval() = val.as_balance();
+ return *this;
+ case BALANCE_PAIR:
+ as_balance_pair_lval() = val.as_balance_pair();
+ return *this;
+ case STRING:
+ as_string_lval() = val.as_string();
+ return *this;
+ case SEQUENCE:
+ as_sequence_lval() = val.as_sequence();
+ return *this;
+ }
+
+ switch (val.type()) {
+ case VOID:
+ set_type(VOID);
+ break;
+
+ case BOOLEAN:
+ set_boolean(val.as_boolean());
+ break;
+ case INTEGER:
+ set_long(val.as_long());
+ break;
+ case DATETIME:
+ set_datetime(val.as_datetime());
+ break;
+ case AMOUNT:
+ set_amount(val.as_amount());
+ break;
+ case BALANCE:
+ set_balance(val.as_balance());
+ break;
+ case BALANCE_PAIR:
+ set_balance_pair(val.as_balance_pair());
+ break;
+ case STRING:
+ set_string(val.as_string());
+ break;
+ case SEQUENCE:
+ set_sequence(val.as_sequence());
+ break;
+ case XML_NODE:
+ set_xml_node(val.as_xml_node());
+ break;
+ case POINTER:
+ set_pointer(val.as_pointer());
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+
+ return *this;
+}
+
+value_t::operator bool() const
+{
+ switch (type()) {
+ case BOOLEAN:
+ return as_boolean();
+ case INTEGER:
+ return as_long();
+ case DATETIME:
+ return is_valid_moment(as_datetime());
+ case AMOUNT:
+ return as_amount();
+ case BALANCE:
+ return as_balance();
+ case BALANCE_PAIR:
+ return as_balance_pair();
+ case STRING:
+ return ! as_string().empty();
+ case SEQUENCE:
+ return ! as_sequence().empty();
+ case XML_NODE:
+ return as_xml_node()->to_value();
+ case POINTER:
+ return as_pointer() != NULL;
+ default:
+ assert(false);
+ break;
+ }
+ assert(false);
+ return 0;
+}
+
bool value_t::to_boolean() const
{
- if (type == BOOLEAN) {
+ if (is_boolean()) {
return as_boolean();
} else {
value_t temp(*this);
@@ -47,7 +200,7 @@ bool value_t::to_boolean() const
long value_t::to_long() const
{
- if (type == INTEGER) {
+ if (is_long()) {
return as_long();
} else {
value_t temp(*this);
@@ -58,7 +211,7 @@ long value_t::to_long() const
moment_t value_t::to_datetime() const
{
- if (type == DATETIME) {
+ if (is_datetime()) {
return as_datetime();
} else {
value_t temp(*this);
@@ -69,7 +222,7 @@ moment_t value_t::to_datetime() const
amount_t value_t::to_amount() const
{
- if (type == AMOUNT) {
+ if (is_amount()) {
return as_amount();
} else {
value_t temp(*this);
@@ -80,7 +233,7 @@ amount_t value_t::to_amount() const
balance_t value_t::to_balance() const
{
- if (type == BALANCE) {
+ if (is_balance()) {
return as_balance();
} else {
value_t temp(*this);
@@ -91,7 +244,7 @@ balance_t value_t::to_balance() const
balance_pair_t value_t::to_balance_pair() const
{
- if (type == BALANCE_PAIR) {
+ if (is_balance_pair()) {
return as_balance_pair();
} else {
value_t temp(*this);
@@ -102,7 +255,7 @@ balance_pair_t value_t::to_balance_pair() const
string value_t::to_string() const
{
- if (type == STRING) {
+ if (is_string()) {
return as_string();
} else {
value_t temp(*this);
@@ -113,7 +266,7 @@ string value_t::to_string() const
value_t::sequence_t value_t::to_sequence() const
{
- if (type == SEQUENCE) {
+ if (is_sequence()) {
return as_sequence();
} else {
value_t temp(*this);
@@ -123,211 +276,99 @@ value_t::sequence_t value_t::to_sequence() const
}
-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:
- ((string *)data)->~string();
- break;
- case SEQUENCE:
- ((sequence_t *)data)->~sequence_t();
- break;
-
- default:
- break;
- }
-}
-
void value_t::in_place_simplify()
{
LOGGER("amounts.values.simplify");
if (is_realzero()) {
- DEBUG_("Zeroing type " << type);
- destroy();
- type = INTEGER;
- as_long() = 0L;
+ DEBUG_("Zeroing type " << type());
+ set_long(0L);
return;
}
- if (type == BALANCE_PAIR &&
+ if (is_type(BALANCE_PAIR) &&
(! as_balance_pair().cost || as_balance_pair().cost->is_realzero())) {
DEBUG_("Reducing balance pair to balance");
in_place_cast(BALANCE);
}
- if (type == BALANCE && as_balance().amounts.size() == 1) {
+ if (is_type(BALANCE) && as_balance().amounts.size() == 1) {
DEBUG_("Reducing balance to amount");
in_place_cast(AMOUNT);
}
- if (type == AMOUNT && ! as_amount().has_commodity() &&
+#if 0
+ if (is_type(AMOUNT) && ! as_amount().has_commodity() &&
as_amount().fits_in_long()) {
DEBUG_("Reducing amount to integer");
in_place_cast(INTEGER);
}
-}
-
-value_t& value_t::operator=(const value_t& val)
-{
- if (this == &val)
- return *this;
-
- if (type == val.type)
- switch (type) {
- case BOOLEAN:
- as_boolean() = val.as_boolean();
- return *this;
- case INTEGER:
- as_long() = val.as_long();
- return *this;
- case DATETIME:
- as_datetime() = val.as_datetime();
- return *this;
- case AMOUNT:
- as_amount() = val.as_amount();
- return *this;
- case BALANCE:
- as_balance() = val.as_balance();
- return *this;
- case BALANCE_PAIR:
- as_balance_pair() = val.as_balance_pair();
- return *this;
- case STRING:
- as_string() = val.as_string();
- return *this;
- case SEQUENCE:
- as_sequence() = val.as_sequence();
- return *this;
- }
-
- destroy();
-
- type = val.type;
-
- switch (val.type) {
- case VOID:
- break;
-
- case BOOLEAN:
- as_boolean() = val.as_boolean();
- break;
-
- case INTEGER:
- as_long() = val.as_long();
- break;
-
- case DATETIME:
- new((moment_t *) data) moment_t(val.as_datetime());
- break;
-
- case AMOUNT:
- new((amount_t *)data) amount_t(val.as_amount());
- break;
-
- case BALANCE:
- new((balance_t *)data) balance_t(val.as_balance());
- break;
-
- case BALANCE_PAIR:
- new((balance_pair_t *)data) balance_pair_t(val.as_balance_pair());
- break;
-
- case STRING:
- new((string *)data) string(val.as_string());
- break;
-
- case SEQUENCE:
- new((sequence_t *)data) sequence_t(val.as_sequence());
- break;
-
- case XML_NODE:
- as_xml_node() = val.as_xml_node();
- break;
-
- case POINTER:
- as_pointer() = val.as_pointer();
- break;
-
- default:
- assert(false);
- break;
- }
-
- return *this;
+#endif
}
value_t& value_t::operator+=(const value_t& val)
{
- if (type == STRING) {
- if (val.type == STRING)
- as_string() += val.as_string();
+ if (is_type(STRING)) {
+ if (val.is_type(STRING))
+ as_string_lval() += val.as_string();
else
- as_string() += val.to_string();
+ as_string_lval() += val.to_string();
return *this;
}
- else if (type == SEQUENCE) {
- if (val.type == SEQUENCE)
- as_sequence().insert(as_sequence().end(),
- val.as_sequence().begin(),
- val.as_sequence().end());
- else
- as_sequence().push_back(val);
+ else if (is_type(SEQUENCE)) {
+ if (val.is_type(SEQUENCE)) {
+ sequence_t& seq(as_sequence_lval());
+ seq.insert(seq.end(), val.as_sequence().begin(),
+ val.as_sequence().end());
+ } else {
+ as_sequence_lval().push_back(val);
+ }
return *this;
}
- if (val.type == XML_NODE) // recurse
+ if (val.is_type(XML_NODE)) // recurse
return *this += val.as_xml_node()->to_value();
- switch (type) {
+ switch (type()) {
case DATETIME:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
- as_datetime() += date_duration(val.as_long());
+ as_datetime_lval() += date_duration(val.as_long());
return *this;
case AMOUNT:
- as_datetime() += date_duration(val.as_amount().to_long());
+ as_datetime_lval() += date_duration(val.as_amount().to_long());
return *this;
}
break;
case INTEGER:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
- as_long() += val.as_long();
+ as_long_lval() += val.as_long();
return *this;
case AMOUNT:
in_place_cast(AMOUNT);
- as_amount() += val.as_amount();
+ as_amount_lval() += val.as_amount();
return *this;
case BALANCE:
in_place_cast(BALANCE);
- as_balance() += val.as_balance();
+ as_balance_lval() += val.as_balance();
return *this;
case BALANCE_PAIR:
in_place_cast(BALANCE_PAIR);
- as_balance_pair() += val.as_balance_pair();
+ as_balance_pair_lval() += val.as_balance_pair();
return *this;
}
break;
case AMOUNT:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
if (as_amount().has_commodity()) {
in_place_cast(BALANCE);
return *this += val;
} else {
- as_amount() += val.as_long();
+ as_amount_lval() += val.as_long();
return *this;
}
break;
@@ -337,125 +378,125 @@ value_t& value_t::operator+=(const value_t& val)
in_place_cast(BALANCE);
return *this += val;
} else {
- as_amount() += val.as_amount();
+ as_amount_lval() += val.as_amount();
return *this;
}
break;
case BALANCE:
in_place_cast(BALANCE);
- as_balance() += val.as_balance();
+ as_balance_lval() += val.as_balance();
return *this;
case BALANCE_PAIR:
in_place_cast(BALANCE_PAIR);
- as_balance_pair() += val.as_balance_pair();
+ as_balance_pair_lval() += val.as_balance_pair();
return *this;
}
break;
case BALANCE:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
- as_balance() += val.to_amount();
+ as_balance_lval() += val.to_amount();
return *this;
case AMOUNT:
- as_balance() += val.as_amount();
+ as_balance_lval() += val.as_amount();
return *this;
case BALANCE:
- as_balance() += val.as_balance();
+ as_balance_lval() += val.as_balance();
return *this;
case BALANCE_PAIR:
in_place_cast(BALANCE_PAIR);
- as_balance_pair() += val.as_balance_pair();
+ as_balance_pair_lval() += val.as_balance_pair();
return *this;
}
break;
case BALANCE_PAIR:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
- as_balance_pair() += val.to_amount();
+ as_balance_pair_lval() += val.to_amount();
return *this;
case AMOUNT:
- as_balance_pair() += val.as_amount();
+ as_balance_pair_lval() += val.as_amount();
return *this;
case BALANCE:
- as_balance_pair() += val.as_balance();
+ as_balance_pair_lval() += val.as_balance();
return *this;
case BALANCE_PAIR:
- as_balance_pair() += val.as_balance_pair();
+ as_balance_pair_lval() += val.as_balance_pair();
return *this;
}
break;
}
- throw_(value_error,
- "Cannot add " << label() << " to " << val.label());
+ throw_(value_error, "Cannot add " << label() << " to " << val.label());
+
return *this;
}
value_t& value_t::operator-=(const value_t& val)
{
- if (type == SEQUENCE) {
- if (val.type == SEQUENCE) {
+ if (is_type(SEQUENCE)) {
+ sequence_t& seq(as_sequence_lval());
+
+ if (val.is_type(SEQUENCE)) {
for (sequence_t::const_iterator i = val.as_sequence().begin();
i != val.as_sequence().end();
i++) {
- sequence_t::iterator j =
- std::find(as_sequence().begin(), as_sequence().end(), *i);
- if (j != as_sequence().end())
- as_sequence().erase(j);
+ sequence_t::iterator j = std::find(seq.begin(), seq.end(), *i);
+ if (j != seq.end())
+ seq.erase(j);
}
} else {
- sequence_t::iterator i =
- std::find(as_sequence().begin(), as_sequence().end(), val);
- if (i != as_sequence().end())
- as_sequence().erase(i);
+ sequence_t::iterator i = std::find(seq.begin(), seq.end(), val);
+ if (i != seq.end())
+ seq.erase(i);
}
return *this;
}
- if (val.type == XML_NODE) // recurse
+ if (val.is_type(XML_NODE)) // recurse
return *this -= val.as_xml_node()->to_value();
- switch (type) {
+ switch (type()) {
case DATETIME:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
- as_datetime() -= date_duration(val.as_long());
+ as_datetime_lval() -= date_duration(val.as_long());
return *this;
case AMOUNT:
- as_datetime() -= date_duration(val.as_amount().to_long());
+ as_datetime_lval() -= date_duration(val.as_amount().to_long());
return *this;
}
break;
case INTEGER:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
- as_long() -= val.as_long();
+ as_long_lval() -= val.as_long();
return *this;
case AMOUNT:
in_place_cast(AMOUNT);
- as_amount() -= val.as_amount();
+ as_amount_lval() -= val.as_amount();
in_place_simplify();
return *this;
case BALANCE:
in_place_cast(BALANCE);
- as_balance() -= val.as_balance();
+ as_balance_lval() -= val.as_balance();
in_place_simplify();
return *this;
case BALANCE_PAIR:
in_place_cast(BALANCE_PAIR);
- as_balance_pair() -= val.as_balance_pair();
+ as_balance_pair_lval() -= val.as_balance_pair();
in_place_simplify();
return *this;
}
break;
case AMOUNT:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
if (as_amount().has_commodity()) {
in_place_cast(BALANCE);
@@ -463,7 +504,7 @@ value_t& value_t::operator-=(const value_t& val)
in_place_simplify();
return *this;
} else {
- as_amount() -= val.as_long();
+ as_amount_lval() -= val.as_long();
in_place_simplify();
return *this;
}
@@ -476,7 +517,7 @@ value_t& value_t::operator-=(const value_t& val)
in_place_simplify();
return *this;
} else {
- as_amount() -= val.as_amount();
+ as_amount_lval() -= val.as_amount();
in_place_simplify();
return *this;
}
@@ -484,78 +525,78 @@ value_t& value_t::operator-=(const value_t& val)
case BALANCE:
in_place_cast(BALANCE);
- as_balance() -= val.as_balance();
+ as_balance_lval() -= val.as_balance();
in_place_simplify();
return *this;
case BALANCE_PAIR:
in_place_cast(BALANCE_PAIR);
- as_balance_pair() -= val.as_balance_pair();
+ as_balance_pair_lval() -= val.as_balance_pair();
in_place_simplify();
return *this;
}
break;
case BALANCE:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
- as_balance() -= val.to_amount();
+ as_balance_lval() -= val.to_amount();
in_place_simplify();
return *this;
case AMOUNT:
- as_balance() -= val.as_amount();
+ as_balance_lval() -= val.as_amount();
in_place_simplify();
return *this;
case BALANCE:
- as_balance() -= val.as_balance();
+ as_balance_lval() -= val.as_balance();
in_place_simplify();
return *this;
case BALANCE_PAIR:
in_place_cast(BALANCE_PAIR);
- as_balance_pair() -= val.as_balance_pair();
+ as_balance_pair_lval() -= val.as_balance_pair();
in_place_simplify();
return *this;
}
break;
case BALANCE_PAIR:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
- as_balance_pair() -= val.to_amount();
+ as_balance_pair_lval() -= val.to_amount();
in_place_simplify();
return *this;
case AMOUNT:
- as_balance_pair() -= val.as_amount();
+ as_balance_pair_lval() -= val.as_amount();
in_place_simplify();
return *this;
case BALANCE:
- as_balance_pair() -= val.as_balance();
+ as_balance_pair_lval() -= val.as_balance();
in_place_simplify();
return *this;
case BALANCE_PAIR:
- as_balance_pair() -= val.as_balance_pair();
+ as_balance_pair_lval() -= val.as_balance_pair();
in_place_simplify();
return *this;
}
break;
}
- throw_(value_error,
- "Cannot subtract " << label() << " from " << val.label());
+ throw_(value_error, "Cannot subtract " << label() << " from " << val.label());
+
return *this;
}
value_t& value_t::operator*=(const value_t& val)
{
- if (type == STRING) {
+ if (is_type(STRING)) {
string temp;
long count = val.to_long();
for (long i = 0; i < count; i++)
temp += as_string();
- as_string() = temp;
+ set_string(temp);
return *this;
}
- else if (type == SEQUENCE) {
+ else if (is_type(SEQUENCE)) {
value_t temp;
long count = val.to_long();
for (long i = 0; i < count; i++)
@@ -563,34 +604,31 @@ value_t& value_t::operator*=(const value_t& val)
return *this = temp;
}
- if (val.type == XML_NODE) // recurse
+ if (val.is_type(XML_NODE)) // recurse
return *this *= val.as_xml_node()->to_value();
- switch (type) {
+ switch (type()) {
case INTEGER:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
- as_long() *= val.as_long();
+ as_long_lval() *= val.as_long();
return *this;
- case AMOUNT: {
- long temp = as_long();
- in_place_cast(AMOUNT);
- as_amount() = val.as_amount() * temp;
+ case AMOUNT:
+ set_amount(val.as_amount() * as_long());
return *this;
}
- }
break;
case AMOUNT:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
- as_amount() *= val.as_long();
+ as_amount_lval() *= val.as_long();
return *this;
case AMOUNT:
if (as_amount().commodity() == val.as_amount().commodity() ||
! val.as_amount().has_commodity()) {
- as_amount() *= val.as_amount();
+ as_amount_lval() *= val.as_amount();
return *this;
}
break;
@@ -598,13 +636,13 @@ value_t& value_t::operator*=(const value_t& val)
break;
case BALANCE:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
- as_balance() *= val.as_long();
+ as_balance_lval() *= val.as_long();
return *this;
case AMOUNT:
if (! val.as_amount().has_commodity()) {
- as_balance() *= val.as_amount();
+ as_balance_lval() *= val.as_amount();
return *this;
}
break;
@@ -612,13 +650,13 @@ value_t& value_t::operator*=(const value_t& val)
break;
case BALANCE_PAIR:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
- as_balance_pair() *= val.as_long();
+ as_balance_pair_lval() *= val.as_long();
return *this;
case AMOUNT:
if (! val.as_amount().has_commodity()) {
- as_balance_pair() *= val.as_amount();
+ as_balance_pair_lval() *= val.as_amount();
return *this;
}
break;
@@ -626,41 +664,38 @@ value_t& value_t::operator*=(const value_t& val)
break;
}
- throw_(value_error,
- "Cannot multiply " << label() << " with " << val.label());
+ throw_(value_error, "Cannot multiply " << label() << " with " << val.label());
+
return *this;
}
value_t& value_t::operator/=(const value_t& val)
{
- if (val.type == XML_NODE) // recurse
+ if (val.is_type(XML_NODE)) // recurse
return *this /= val.as_xml_node()->to_value();
- switch (type) {
+ switch (type()) {
case INTEGER:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
- as_long() /= val.as_long();
+ as_long_lval() /= val.as_long();
return *this;
- case AMOUNT: {
- long temp = as_long();
- in_place_cast(AMOUNT);
- as_amount() = val.as_amount() / temp;
+ case AMOUNT:
+ set_amount(val.as_amount() / as_long());
return *this;
}
- }
break;
case AMOUNT:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
- as_amount() /= val.as_long();
+ as_amount_lval() /= val.as_long();
return *this;
case AMOUNT:
if (as_amount().commodity() == val.as_amount().commodity() ||
! val.as_amount().has_commodity()) {
- as_amount() /= val.as_amount();
+ as_amount_lval() /= val.as_amount();
return *this;
}
break;
@@ -668,13 +703,13 @@ value_t& value_t::operator/=(const value_t& val)
break;
case BALANCE:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
- as_balance() /= val.as_long();
+ as_balance_lval() /= val.as_long();
return *this;
case AMOUNT:
if (! val.as_amount().has_commodity()) {
- as_balance() /= val.as_amount();
+ as_balance_lval() /= val.as_amount();
return *this;
}
break;
@@ -682,13 +717,13 @@ value_t& value_t::operator/=(const value_t& val)
break;
case BALANCE_PAIR:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
- as_balance_pair() /= val.as_long();
+ as_balance_pair_lval() /= val.as_long();
return *this;
case AMOUNT:
if (! val.as_amount().has_commodity()) {
- as_balance_pair() /= val.as_amount();
+ as_balance_pair_lval() /= val.as_amount();
return *this;
}
break;
@@ -696,34 +731,34 @@ value_t& value_t::operator/=(const value_t& val)
break;
}
- throw_(value_error,
- "Cannot divide " << label() << " by " << val.label());
+ throw_(value_error, "Cannot divide " << label() << " by " << val.label());
+
return *this;
}
bool value_t::operator==(const value_t& val) const
{
- if (type == XML_NODE && val.type == XML_NODE)
+ if (is_type(XML_NODE) && val.is_type(XML_NODE))
return as_xml_node() == val.as_xml_node();
- else if (type == XML_NODE)
+ else if (is_type(XML_NODE))
return as_xml_node()->to_value() == val;
- else if (val.type == XML_NODE)
+ else if (val.is_type(XML_NODE))
return *this == val.as_xml_node()->to_value();
- switch (type) {
+ switch (type()) {
case BOOLEAN:
- if (val.type == BOOLEAN)
+ if (val.is_type(BOOLEAN))
return as_boolean() == val.as_boolean();
break;
case DATETIME:
- if (val.type == DATETIME)
+ if (val.is_type(DATETIME))
return as_datetime() == val.as_datetime();
break;
case INTEGER:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
return as_long() == val.as_long();
case AMOUNT:
@@ -738,7 +773,7 @@ bool value_t::operator==(const value_t& val) const
break;
case AMOUNT:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
return as_amount() == val.as_long();
case AMOUNT:
@@ -753,7 +788,7 @@ bool value_t::operator==(const value_t& val) const
break;
case BALANCE:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
return as_balance() == val.to_amount();
case AMOUNT:
@@ -768,7 +803,7 @@ bool value_t::operator==(const value_t& val) const
break;
case BALANCE_PAIR:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
return as_balance_pair() == val.to_amount();
case AMOUNT:
@@ -783,17 +818,17 @@ bool value_t::operator==(const value_t& val) const
break;
case STRING:
- if (val.type == STRING)
+ if (val.is_type(STRING))
return as_string() == val.as_string();
break;
case SEQUENCE:
- if (val.type == SEQUENCE)
+ if (val.is_type(SEQUENCE))
return as_sequence() == val.as_sequence();
break;
case POINTER:
- if (val.type == POINTER)
+ if (val.is_type(POINTER))
return as_pointer() == val.as_pointer();
break;
@@ -801,29 +836,28 @@ bool value_t::operator==(const value_t& val) const
break;
}
- throw_(value_error,
- "Cannot compare " << label() << " to " << val.label());
+ throw_(value_error, "Cannot compare " << label() << " to " << val.label());
return *this;
}
bool value_t::operator<(const value_t& val) const
{
- if (type == XML_NODE && val.type == XML_NODE)
+ if (is_type(XML_NODE) && val.is_type(XML_NODE))
return as_xml_node() < val.as_xml_node();
- else if (type == XML_NODE)
+ else if (is_type(XML_NODE))
return as_xml_node()->to_value() < val;
- else if (val.type == XML_NODE)
+ else if (val.is_type(XML_NODE))
return *this < val.as_xml_node()->to_value();
- switch (type) {
+ switch (type()) {
case DATETIME:
- if (val.type == DATETIME)
+ if (val.is_type(DATETIME))
return as_datetime() < val.as_datetime();
break;
case INTEGER:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
return as_long() < val.as_long();
case AMOUNT:
@@ -834,7 +868,7 @@ bool value_t::operator<(const value_t& val) const
break;
case AMOUNT:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
return as_amount() < val.as_long();
case AMOUNT:
@@ -845,12 +879,12 @@ bool value_t::operator<(const value_t& val) const
break;
case STRING:
- if (val.type == STRING)
+ if (val.is_type(STRING))
return as_string() < val.as_string();
break;
case POINTER:
- if (val.type == POINTER)
+ if (val.is_type(POINTER))
return as_pointer() < val.as_pointer();
break;
@@ -858,8 +892,7 @@ bool value_t::operator<(const value_t& val) const
break;
}
- throw_(value_error,
- "Cannot compare " << label() << " to " << val.label());
+ throw_(value_error, "Cannot compare " << label() << " to " << val.label());
return *this;
}
@@ -867,21 +900,21 @@ bool value_t::operator<(const value_t& val) const
#if 0
bool value_t::operator>(const value_t& val) const
{
- if (type == XML_NODE && val.type == XML_NODE)
+ if (is_type(XML_NODE) && val.is_type(XML_NODE))
return as_xml_node() > val.as_xml_node();
- else if (type == XML_NODE)
+ else if (is_type(XML_NODE))
return as_xml_node()->to_value() > val;
- else if (val.type == XML_NODE)
+ else if (val.is_type(XML_NODE))
return *this > val.as_xml_node()->to_value();
- switch (type) {
+ switch (type()) {
case DATETIME:
- if (val.type == DATETIME)
+ if (val.is_type(DATETIME))
return as_datetime() > val.as_datetime();
break;
case INTEGER:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
return as_long() > val.as_long();
case AMOUNT:
@@ -892,7 +925,7 @@ bool value_t::operator>(const value_t& val) const
break;
case AMOUNT:
- switch (val.type) {
+ switch (val.type()) {
case INTEGER:
return as_amount() > val.as_long();
case AMOUNT:
@@ -903,12 +936,12 @@ bool value_t::operator>(const value_t& val) const
break;
case STRING:
- if (val.type == STRING)
+ if (val.is_type(STRING))
return as_string() > val.as_string();
break;
case POINTER:
- if (val.type == POINTER)
+ if (val.is_type(POINTER))
return as_pointer() > val.as_pointer();
break;
@@ -923,72 +956,35 @@ bool value_t::operator>(const value_t& val) const
}
#endif
-value_t::operator bool() const
-{
- switch (type) {
- case BOOLEAN:
- return as_boolean();
- case INTEGER:
- return as_long();
- case DATETIME:
- return is_valid_moment(as_datetime());
- case AMOUNT:
- return as_amount();
- case BALANCE:
- return as_balance();
- case BALANCE_PAIR:
- return as_balance_pair();
- case STRING:
- return ! as_string().empty();
- case SEQUENCE:
- return ! as_sequence().empty();
- case XML_NODE:
- return as_xml_node()->to_value();
- case POINTER:
- return as_pointer() != NULL;
- default:
- assert(false);
- break;
- }
- assert(false);
- return 0;
-}
-
void value_t::in_place_cast(type_t cast_type)
{
- if (type == cast_type)
+ if (type() == cast_type)
return;
if (cast_type == BOOLEAN) {
- bool truth(*this);
- destroy();
- type = BOOLEAN;
- as_boolean() = truth;
+ set_boolean(bool(*this));
return;
}
else if (cast_type == SEQUENCE) {
- value_t temp(*this);
- destroy();
- type = SEQUENCE;
- new((sequence_t *)data) sequence_t;
- as_sequence().push_back(temp);
+ sequence_t temp;
+ temp.push_back(*this);
+ set_sequence(temp);
return;
}
// This must came after the if's above, otherwise it would be
// impossible to turn an XML node into a sequence containing that
// same XML node.
- if (type == XML_NODE) {
+ if (is_type(XML_NODE)) {
*this = as_xml_node()->to_value().cast(cast_type);
return;
}
- switch (type) {
+ switch (type()) {
case BOOLEAN:
switch (cast_type) {
case STRING:
- new((string *)data) string(as_boolean() ? "true" : "false");
- type = cast_type;
+ set_string(as_boolean() ? "true" : "false");
return;
}
break;
@@ -996,132 +992,90 @@ void value_t::in_place_cast(type_t cast_type)
case INTEGER:
switch (cast_type) {
case AMOUNT:
- new((amount_t *)data) amount_t(as_long());
- type = cast_type;
+ set_amount(as_long());
return;
case BALANCE:
- new((balance_t *)data) balance_t(as_long());
- type = cast_type;
+ set_balance(to_amount());
return;
case BALANCE_PAIR:
- new((balance_pair_t *)data) balance_pair_t(as_long());
- type = cast_type;
+ set_balance_pair(to_amount());
return;
case STRING:
- new((string *)data) string(lexical_cast<string>(as_long()));
- type = cast_type;
+ set_string(lexical_cast<string>(as_long()));
return;
}
break;
case AMOUNT:
switch (cast_type) {
- case INTEGER: {
- long temp = as_amount().to_long();
- destroy();
- type = cast_type;
- as_long() = temp;
+ case INTEGER:
+ set_long(as_amount().to_long());
return;
- }
- case BALANCE: {
- amount_t temp = as_amount();
- destroy();
- type = cast_type;
- new((balance_t *)data) balance_t(temp);
+ case BALANCE:
+ set_balance(as_amount());
return;
- }
- case BALANCE_PAIR: {
- amount_t temp = as_amount();
- destroy();
- type = cast_type;
- new((balance_pair_t *)data) balance_pair_t(temp);
+ case BALANCE_PAIR:
+ set_balance_pair(as_amount());
return;
- }
- case STRING: {
- amount_t temp = as_amount();
- destroy();
- type = cast_type;
- new((string *)data) string(temp.to_string());
+ case STRING:
+ set_string(as_amount().to_string());
return;
}
- }
break;
case BALANCE:
switch (cast_type) {
case AMOUNT: {
- balance_t& temp(as_balance());
+ const balance_t& temp(as_balance());
if (temp.amounts.size() == 1) {
- amount_t amt = (*temp.amounts.begin()).second;
- destroy();
- type = cast_type;
- new((amount_t *)data) amount_t(amt);
+ set_amount((*temp.amounts.begin()).second);
return;
}
else if (temp.amounts.size() == 0) {
- destroy();
- type = cast_type;
- new((amount_t *)data) amount_t(0L);
+ set_amount(0L);
return;
}
else {
- throw_(value_error,
- "Cannot convert " << label() <<
+ throw_(value_error, "Cannot convert " << label() <<
" with multiple commodities to " << label(cast_type));
}
break;
}
- case BALANCE_PAIR: {
- balance_t temp = as_balance();
- destroy();
- type = cast_type;
- new((balance_pair_t *)data) balance_pair_t(temp);
+ case BALANCE_PAIR:
+ set_balance_pair(as_balance());
return;
}
- }
break;
case BALANCE_PAIR:
switch (cast_type) {
case AMOUNT: {
- balance_t& temp(as_balance_pair().quantity);
+ const balance_t& temp(as_balance_pair().quantity);
if (temp.amounts.size() == 1) {
- amount_t amt = (*temp.amounts.begin()).second;
- destroy();
- type = cast_type;
- new((amount_t *)data) amount_t(amt);
+ set_amount((*temp.amounts.begin()).second);
return;
}
else if (temp.amounts.size() == 0) {
- type = cast_type;
- new((amount_t *)data) amount_t(0L);
+ set_amount(0L);
return;
}
else {
- throw_(value_error,
- "Cannot convert " << label() <<
+ throw_(value_error, "Cannot convert " << label() <<
" with multiple commodities to " << label(cast_type));
}
break;
}
- case BALANCE: {
- balance_t temp = as_balance_pair().quantity;
- destroy();
- type = cast_type;
- new((balance_t *)data) balance_t(temp);
+ case BALANCE:
+ set_balance(as_balance_pair().quantity);
return;
}
- }
break;
case STRING:
switch (cast_type) {
case INTEGER: {
if (all(as_string(), is_digit())) {
- long temp = lexical_cast<long>(as_string());
- destroy();
- type = cast_type;
- as_long() = temp;
+ set_long(lexical_cast<long>(as_string()));
return;
} else {
throw_(value_error,
@@ -1130,14 +1084,10 @@ void value_t::in_place_cast(type_t cast_type)
break;
}
- case AMOUNT: {
- amount_t temp(as_string());
- destroy();
- type = cast_type;
- new((amount_t *)data) amount_t(temp);
+ case AMOUNT:
+ set_amount(as_string());
return;
}
- }
break;
}
@@ -1147,21 +1097,21 @@ void value_t::in_place_cast(type_t cast_type)
void value_t::in_place_negate()
{
- switch (type) {
+ switch (type()) {
case BOOLEAN:
- as_boolean() = ! as_boolean();
+ set_boolean(! as_boolean());
return;
case INTEGER:
- as_long() = - as_long();
+ set_long(- as_long());
return;
case AMOUNT:
- as_amount().in_place_negate();
+ as_amount_lval().in_place_negate();
return;
case BALANCE:
- as_balance().in_place_negate();
+ as_balance_lval().in_place_negate();
return;
case BALANCE_PAIR:
- as_balance_pair().in_place_negate();
+ as_balance_pair_lval().in_place_negate();
return;
case XML_NODE:
*this = as_xml_node()->to_value();
@@ -1174,7 +1124,7 @@ void value_t::in_place_negate()
bool value_t::is_realzero() const
{
- switch (type) {
+ switch (type()) {
case BOOLEAN:
return ! as_boolean();
case INTEGER:
@@ -1207,7 +1157,7 @@ bool value_t::is_realzero() const
value_t value_t::value(const optional<moment_t>& moment) const
{
- switch (type) {
+ switch (type()) {
case INTEGER:
return *this;
@@ -1237,17 +1187,17 @@ value_t value_t::value(const optional<moment_t>& moment) const
void value_t::in_place_reduce()
{
- switch (type) {
+ switch (type()) {
case INTEGER:
break;
case AMOUNT:
- as_amount().in_place_reduce();
+ as_amount_lval().in_place_reduce();
break;
case BALANCE:
- as_balance().in_place_reduce();
+ as_balance_lval().in_place_reduce();
break;
case BALANCE_PAIR:
- as_balance_pair().in_place_reduce();
+ as_balance_pair_lval().in_place_reduce();
break;
case XML_NODE:
*this = as_xml_node()->to_value();
@@ -1260,7 +1210,7 @@ void value_t::in_place_reduce()
value_t value_t::round() const
{
- switch (type) {
+ switch (type()) {
case INTEGER:
return *this;
case AMOUNT:
@@ -1279,7 +1229,7 @@ value_t value_t::round() const
value_t value_t::unround() const
{
- switch (type) {
+ switch (type()) {
case BOOLEAN:
throw_(value_error, "Cannot un-round a boolean");
case DATETIME:
@@ -1307,7 +1257,7 @@ value_t value_t::unround() const
value_t value_t::annotated_price() const
{
- switch (type) {
+ switch (type()) {
case BOOLEAN:
throw_(value_error, "Cannot find the annotated price of a boolean");
case INTEGER:
@@ -1347,7 +1297,7 @@ value_t value_t::annotated_price() const
value_t value_t::annotated_date() const
{
- switch (type) {
+ switch (type()) {
case BOOLEAN:
throw_(value_error, "Cannot find the annotated date of a boolean");
case INTEGER:
@@ -1388,7 +1338,7 @@ value_t value_t::annotated_date() const
value_t value_t::annotated_tag() const
{
- switch (type) {
+ switch (type()) {
case BOOLEAN:
throw_(value_error, "Cannot find the annotated tag of a boolean");
case INTEGER:
@@ -1431,7 +1381,7 @@ value_t value_t::strip_annotations(const bool keep_price,
const bool keep_date,
const bool keep_tag) const
{
- switch (type) {
+ switch (type()) {
case BOOLEAN:
case INTEGER:
case DATETIME:
@@ -1448,14 +1398,12 @@ value_t value_t::strip_annotations(const bool keep_price,
}
case AMOUNT:
- return as_amount().strip_annotations
- (keep_price, keep_date, keep_tag);
+ return as_amount().strip_annotations(keep_price, keep_date, keep_tag);
case BALANCE:
- return as_balance().strip_annotations
- (keep_price, keep_date, keep_tag);
+ return as_balance().strip_annotations(keep_price, keep_date, keep_tag);
case BALANCE_PAIR:
- return as_balance_pair().quantity.strip_annotations
- (keep_price, keep_date, keep_tag);
+ return as_balance_pair().quantity.strip_annotations(keep_price,
+ keep_date, keep_tag);
default:
assert(false);
@@ -1467,7 +1415,7 @@ value_t value_t::strip_annotations(const bool keep_price,
value_t value_t::cost() const
{
- switch (type) {
+ switch (type()) {
case BOOLEAN:
throw_(value_error, "Cannot find the cost of a boolean");
case INTEGER:
@@ -1503,27 +1451,28 @@ value_t value_t::cost() const
value_t& value_t::add(const amount_t& amount, const optional<amount_t>& tcost)
{
- switch (type) {
+ 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 &&
+ else if ((is_type(AMOUNT) &&
as_amount().commodity() != amount.commodity()) ||
- (type != AMOUNT && amount.commodity())) {
+ (! is_type(AMOUNT) && amount.commodity())) {
in_place_cast(BALANCE);
return add(amount, tcost);
}
- else if (type != AMOUNT) {
+ else if (! is_type(AMOUNT)) {
in_place_cast(AMOUNT);
}
- as_amount() += amount;
+ *this += amount;
break;
case BALANCE:
@@ -1531,11 +1480,11 @@ value_t& value_t::add(const amount_t& amount, const optional<amount_t>& tcost)
in_place_cast(BALANCE_PAIR);
return add(amount, tcost);
}
- as_balance() += amount;
+ *this += amount;
break;
case BALANCE_PAIR:
- as_balance_pair().add(amount, tcost);
+ as_balance_pair_lval().add(amount, tcost);
break;
case STRING:
@@ -1558,7 +1507,7 @@ value_t& value_t::add(const amount_t& amount, const optional<amount_t>& tcost)
void value_t::print(std::ostream& out, const int first_width,
const int latter_width) const
{
- switch (type) {
+ switch (type()) {
case BOOLEAN:
case DATETIME:
case INTEGER:
@@ -1601,7 +1550,7 @@ void value_t::print(std::ostream& out, const int first_width,
std::ostream& operator<<(std::ostream& out, const value_t& val)
{
- switch (val.type) {
+ switch (val.type()) {
case value_t::BOOLEAN:
out << (val.as_boolean() ? "true" : "false");
break;
@@ -1676,7 +1625,7 @@ void value_context::describe(std::ostream& out) const throw()
out << std::right;
out.width(20);
- switch (bal->type) {
+ switch (bal->type()) {
case value_t::BOOLEAN:
out << (*((bool *) bal->data) ? "true" : "false");
break;
diff --git a/src/value.h b/src/value.h
index 51b5be22..3e67c248 100644
--- a/src/value.h
+++ b/src/value.h
@@ -58,9 +58,7 @@ class value_t
ordered_field_operators<value_t, unsigned long,
ordered_field_operators<value_t, long> > > > > > >
{
- char data[sizeof(balance_pair_t)];
-
- public:
+public:
typedef std::vector<value_t> sequence_t;
enum type_t {
@@ -75,236 +73,366 @@ class value_t
SEQUENCE,
XML_NODE,
POINTER
- } type;
+ };
+
+private:
+ class storage_t
+ {
+ char data[sizeof(balance_pair_t)];
+ type_t type;
+
+ BOOST_STATIC_ASSERT(sizeof(balance_pair_t) > sizeof(bool));
+ BOOST_STATIC_ASSERT(sizeof(balance_pair_t) > sizeof(moment_t));
+ BOOST_STATIC_ASSERT(sizeof(balance_pair_t) > sizeof(long));
+ BOOST_STATIC_ASSERT(sizeof(balance_pair_t) > sizeof(amount_t));
+ BOOST_STATIC_ASSERT(sizeof(balance_pair_t) > sizeof(balance_t));
+ BOOST_STATIC_ASSERT(sizeof(balance_pair_t) > sizeof(string));
+ BOOST_STATIC_ASSERT(sizeof(balance_pair_t) > sizeof(sequence_t));
+ BOOST_STATIC_ASSERT(sizeof(balance_pair_t) > sizeof(xml::node_t *));
+
+ explicit storage_t() : type(VOID), refc(0) {
+ TRACE_CTOR(value_t::storage_t, "");
+ }
+ explicit storage_t(const storage_t& rhs)
+ : type(rhs.type), refc(0) {
+ TRACE_CTOR(value_t::storage_t, "");
+ std::memcpy(data, rhs.data, sizeof(balance_pair_t));
+ }
+
+ public: // so `checked_delete' can access it
+ ~storage_t() {
+ TRACE_DTOR(value_t::storage_t);
+ DEBUG("value.storage.refcount", "Destroying " << this);
+ assert(refc == 0);
+ destroy();
+ }
+
+ private:
+ storage_t& operator=(const storage_t& rhs) {
+ type = rhs.type;
+ std::memcpy(data, rhs.data, sizeof(balance_pair_t));
+ return *this;
+ }
+
+ mutable int refc;
+
+ void acquire() const {
+ DEBUG("value.storage.refcount",
+ "Acquiring " << this << ", refc now " << refc + 1);
+ assert(refc >= 0);
+ refc++;
+ }
+ void release() const {
+ DEBUG("value.storage.refcount",
+ "Releasing " << this << ", refc now " << refc - 1);
+ assert(refc > 0);
+ if (--refc == 0)
+ checked_delete(this);
+ }
+
+ void destroy();
+
+ friend class value_t;
+
+ friend inline void intrusive_ptr_add_ref(value_t::storage_t * storage) {
+ storage->acquire();
+ }
+ friend inline void intrusive_ptr_release(value_t::storage_t * storage) {
+ storage->release();
+ }
+ };
- value_t() : type(VOID) {
+ intrusive_ptr<storage_t> storage;
+
+ static intrusive_ptr<storage_t> true_value;
+ static intrusive_ptr<storage_t> false_value;
+
+ // jww (2007-05-03): Make this private, and then make
+ // ledger::initialize into a member function of session_t.
+public:
+ static void initialize();
+ static void shutdown();
+
+public:
+ value_t() {
TRACE_CTOR(value_t, "");
}
- value_t(const value_t& val) : type(VOID) {
+ value_t(const value_t& val) {
TRACE_CTOR(value_t, "copy");
*this = val;
}
value_t(const bool val) {
TRACE_CTOR(value_t, "const bool");
- type = BOOLEAN;
- as_boolean() = val;
+ set_boolean(val);
}
value_t(const long val) {
TRACE_CTOR(value_t, "const long");
- type = INTEGER;
- as_long() = val;
+ set_long(val);
}
value_t(const moment_t val) {
TRACE_CTOR(value_t, "const moment_t");
- type = DATETIME;
- new((moment_t *) data) moment_t(val);
+ set_datetime(val);
}
value_t(const double val) {
TRACE_CTOR(value_t, "const double");
- type = AMOUNT;
- new((amount_t *) data) amount_t(val);
+ set_amount(val);
}
value_t(const unsigned long val) {
TRACE_CTOR(value_t, "const unsigned long");
- type = AMOUNT;
- new((amount_t *) data) amount_t(val);
+ set_amount(val);
}
value_t(const string& val, bool literal = false) {
TRACE_CTOR(value_t, "const string&, bool");
- if (literal) {
- type = STRING;
- new((string *) data) string(val);
- } else {
- type = AMOUNT;
- new((amount_t *) data) amount_t(val);
- }
+ if (literal)
+ set_string(val);
+ else
+ set_amount(val);
}
value_t(const char * val, bool literal = false) {
TRACE_CTOR(value_t, "const char *");
- if (literal) {
- type = STRING;
- new((string *) data) string(val);
- } else {
- type = AMOUNT;
- new((amount_t *) data) amount_t(val);
- }
+ if (literal)
+ set_string(val);
+ else
+ set_amount(val);
}
value_t(const amount_t& val) {
TRACE_CTOR(value_t, "const amount_t&");
- type = AMOUNT;
- new((amount_t *)data) amount_t(val);
+ set_amount(val);
}
- value_t(const balance_t& val) : type(VOID) {
+ value_t(const balance_t& val) {
TRACE_CTOR(value_t, "const balance_t&");
- type = BALANCE;
- new((balance_t *)data) balance_t(val);
+ set_balance(val);
}
- value_t(const balance_pair_t& val) : type(VOID) {
+ value_t(const balance_pair_t& val) {
TRACE_CTOR(value_t, "const balance_pair_t&");
- type = BALANCE_PAIR;
- new((balance_pair_t *)data) balance_pair_t(val);
+ set_balance_pair(val);
}
value_t(const sequence_t& val) {
TRACE_CTOR(value_t, "const sequence_t&");
- type = SEQUENCE;
- new((sequence_t *)data) sequence_t(val);
+ set_sequence(val);
}
value_t(xml::node_t * xml_node) {
TRACE_CTOR(value_t, "xml::node_t *");
- type = XML_NODE;
- as_xml_node() = xml_node;
+ set_xml_node(xml_node);
}
value_t(void * item) {
TRACE_CTOR(value_t, "void *");
- type = POINTER;
- as_pointer() = item;
+ set_pointer(item);
}
-
~value_t() {
TRACE_DTOR(value_t);
- destroy();
}
- void destroy();
- value_t simplify() const {
- value_t temp = *this;
- temp.in_place_simplify();
- return temp;
+ value_t& operator=(const value_t& val);
+
+ /**
+ * _dup() makes a private copy of the current value so that it can
+ * subsequently be modified.
+ *
+ * _clear() removes our pointer to the current value and initializes
+ * a new value for things to be stored in.
+ */
+ void _dup() {
+ assert(storage);
+ if (storage->refc > 1)
+ storage = new storage_t(*storage.get());
+ }
+ void _clear() {
+ if (! storage || storage->refc > 1)
+ storage = new storage_t;
+ else
+ storage->destroy();
}
- void in_place_simplify();
- value_t& operator=(const value_t& val);
+ operator bool() const;
- value_t& set_string(const string& str = "") {
- if (type != STRING) {
- destroy();
- type = STRING;
- new((string *) data) string(str);
- } else {
- as_string() = str;
- }
- return *this;
+ bool is_null() const {
+ return ! storage || storage->type == VOID;
+ }
+
+ type_t type() const {
+ return storage ? storage->type : VOID;
+ }
+ bool is_type(type_t _type) const {
+ assert(_type >= VOID && _type <= POINTER);
+ return type() == _type;
+ }
+ void set_type(type_t new_type) {
+ assert(new_type >= VOID && new_type <= POINTER);
+ _clear();
+ storage->type = new_type;
+ assert(is_type(new_type));
}
bool is_boolean() const {
- return type == BOOLEAN;
+ return is_type(BOOLEAN);
}
- bool& as_boolean() {
- assert(type == BOOLEAN);
- return *(bool *) data;
+ bool& as_boolean_lval() {
+ assert(is_boolean());
+ _dup();
+ return *(bool *) storage->data;
}
const bool& as_boolean() const {
- assert(type == BOOLEAN);
- return *(bool *) data;
+ assert(is_boolean());
+ return *(bool *) storage->data;
+ }
+ void set_boolean(const bool val) {
+ set_type(BOOLEAN);
+ storage = val ? true_value : false_value;
}
bool is_long() const {
- return type == INTEGER;
+ return is_type(INTEGER);
}
- long& as_long() {
- assert(type == INTEGER);
- return *(long *) data;
+ long& as_long_lval() {
+ assert(is_long());
+ _dup();
+ return *(long *) storage->data;
}
const long& as_long() const {
- assert(type == INTEGER);
- return *(long *) data;
+ assert(is_long());
+ return *(long *) storage->data;
+ }
+ void set_long(const long val) {
+ set_type(INTEGER);
+ *(long *) storage->data = val;
}
bool is_datetime() const {
- return type == DATETIME;
+ return is_type(DATETIME);
}
- moment_t& as_datetime() {
- assert(type == DATETIME);
- return *(moment_t *) data;
+ moment_t& as_datetime_lval() {
+ assert(is_datetime());
+ _dup();
+ return *(moment_t *) storage->data;
}
const moment_t& as_datetime() const {
- assert(type == DATETIME);
- return *(moment_t *) data;
+ assert(is_datetime());
+ return *(moment_t *) storage->data;
+ }
+ void set_datetime(const moment_t& val) {
+ set_type(DATETIME);
+ new((moment_t *) storage->data) moment_t(val);
}
bool is_amount() const {
- return type == AMOUNT;
+ return is_type(AMOUNT);
}
- amount_t& as_amount() {
- assert(type == AMOUNT);
- return *(amount_t *) data;
+ amount_t& as_amount_lval() {
+ assert(is_amount());
+ _dup();
+ return *(amount_t *) storage->data;
}
const amount_t& as_amount() const {
- assert(type == AMOUNT);
- return *(amount_t *) data;
+ assert(is_amount());
+ return *(amount_t *) storage->data;
+ }
+ void set_amount(const amount_t& val) {
+ set_type(AMOUNT);
+ new((amount_t *) storage->data) amount_t(val);
}
bool is_balance() const {
- return type == BALANCE;
+ return is_type(BALANCE);
}
- balance_t& as_balance() {
- assert(type == BALANCE);
- return *(balance_t *) data;
+ balance_t& as_balance_lval() {
+ assert(is_balance());
+ _dup();
+ return *(balance_t *) storage->data;
}
const balance_t& as_balance() const {
- assert(type == BALANCE);
- return *(balance_t *) data;
+ assert(is_balance());
+ return *(balance_t *) storage->data;
+ }
+ void set_balance(const balance_t& val) {
+ set_type(BALANCE);
+ new((balance_t *) storage->data) balance_t(val);
}
bool is_balance_pair() const {
- return type == BALANCE_PAIR;
+ return is_type(BALANCE_PAIR);
}
- balance_pair_t& as_balance_pair() {
- assert(type == BALANCE_PAIR);
- return *(balance_pair_t *) data;
+ balance_pair_t& as_balance_pair_lval() {
+ assert(is_balance_pair());
+ _dup();
+ return *(balance_pair_t *) storage->data;
}
const balance_pair_t& as_balance_pair() const {
- assert(type == BALANCE_PAIR);
- return *(balance_pair_t *) data;
+ assert(is_balance_pair());
+ return *(balance_pair_t *) storage->data;
+ }
+ void set_balance_pair(const balance_pair_t& val) {
+ set_type(BALANCE_PAIR);
+ new((balance_pair_t *) storage->data) balance_pair_t(val);
}
bool is_string() const {
- return type == STRING;
+ return is_type(STRING);
}
- string& as_string() {
- assert(type == STRING);
- return *(string *) data;
+ string& as_string_lval() {
+ assert(is_string());
+ _dup();
+ return *(string *) storage->data;
}
const string& as_string() const {
- assert(type == STRING);
- return *(string *) data;
+ assert(is_string());
+ return *(string *) storage->data;
+ }
+ void set_string(const string& val = "") {
+ set_type(STRING);
+ new((string *) storage->data) string(val);
}
bool is_sequence() const {
- return type == SEQUENCE;
+ return is_type(SEQUENCE);
}
- sequence_t& as_sequence() {
- assert(type == SEQUENCE);
- return *(sequence_t *) data;
+ sequence_t& as_sequence_lval() {
+ assert(is_sequence());
+ _dup();
+ return *(sequence_t *) storage->data;
}
const sequence_t& as_sequence() const {
- assert(type == SEQUENCE);
- return *(sequence_t *) data;
+ assert(is_sequence());
+ return *(sequence_t *) storage->data;
+ }
+ void set_sequence(const sequence_t& val) {
+ set_type(SEQUENCE);
+ new((sequence_t *) storage->data) sequence_t(val);
}
bool is_xml_node() const {
- return type == XML_NODE;
+ return is_type(XML_NODE);
}
- xml::node_t *& as_xml_node() {
- assert(type == XML_NODE);
- return *(xml::node_t **) data;
+ xml::node_t *& as_xml_node_lval() {
+ assert(is_xml_node());
+ _dup();
+ return *(xml::node_t **) storage->data;
}
xml::node_t * as_xml_node() const {
- assert(type == XML_NODE);
- return *(xml::node_t **) data;
+ assert(is_xml_node());
+ return *(xml::node_t **) storage->data;
+ }
+ void set_xml_node(xml::node_t * val) {
+ set_type(XML_NODE);
+ *(xml::node_t **) storage->data = val;
}
bool is_pointer() const {
- return type == POINTER;
+ return is_type(POINTER);
}
- void *& as_pointer() {
- assert(type == POINTER);
- return *(void **) data;
+ void *& as_pointer_lval() {
+ assert(is_pointer());
+ _dup();
+ return *(void **) storage->data;
}
void * as_pointer() const {
- assert(type == POINTER);
- return *(void **) data;
+ assert(is_pointer());
+ return *(void **) storage->data;
+ }
+ void set_pointer(void * val) {
+ set_type(POINTER);
+ *(void **) storage->data = val;
}
bool to_boolean() const;
@@ -316,15 +444,25 @@ class value_t
string to_string() const;
sequence_t to_sequence() const;
+ value_t simplify() const {
+ value_t temp = *this;
+ temp.in_place_simplify();
+ return temp;
+ }
+ void in_place_simplify();
+
value_t& operator[](const int index) {
+ return as_sequence_lval()[index];
+ }
+ const value_t& operator[](const int index) const {
return as_sequence()[index];
}
void push_back(const value_t& val) {
- return as_sequence().push_back(val);
+ return as_sequence_lval().push_back(val);
}
- std::size_t size() const {
+ const std::size_t size() const {
return as_sequence().size();
}
@@ -335,10 +473,12 @@ class value_t
bool operator==(const value_t& val) const;
bool operator<(const value_t& val) const;
- //bool operator>(const value_t& val) const;
+#if 0
+ bool operator>(const value_t& val) const;
+#endif
string label(optional<type_t> the_type = none) const {
- switch (the_type ? *the_type : type) {
+ switch (the_type ? *the_type : type()) {
case VOID:
return "an uninitialized value";
case BOOLEAN:
@@ -369,8 +509,6 @@ class value_t
return "<invalid>";
}
- operator bool() const;
-
value_t operator-() const {
return negate();
}
@@ -421,19 +559,6 @@ class value_t
std::ostream& operator<<(std::ostream& out, const value_t& val);
-#if 0
-class value_context : public error_context
-{
- value_t * bal;
- public:
- value_context(const value_t& _bal,
- const string& desc = "") throw();
- virtual ~value_context() throw();
-
- virtual void describe(std::ostream& out) const throw();
-};
-#endif
-
DECLARE_EXCEPTION(value_error);
} // namespace ledger
diff --git a/src/xpath.cc b/src/xpath.cc
index eba07428..623aa8c4 100644
--- a/src/xpath.cc
+++ b/src/xpath.cc
@@ -1050,7 +1050,7 @@ xpath_t::op_t::copy(ptr_op_t tleft, ptr_op_t tright) const
return node;
}
-void xpath_t::op_t::find_values(value_t& context, scope_t * scope,
+void xpath_t::op_t::find_values(const value_t& context, scope_t * scope,
value_t::sequence_t& result_seq,
bool recursive)
{
@@ -1062,7 +1062,7 @@ void xpath_t::op_t::find_values(value_t& context, scope_t * scope,
append_value(expr.ptr->as_value(), result_seq);
if (recursive) {
- if (context.type == value_t::XML_NODE) {
+ if (context.is_type(value_t::XML_NODE)) {
node_t * ptr = context.as_xml_node();
if (ptr->is_parent_node())
foreach (node_t * node, ptr->as_parent_node()) {
@@ -1075,14 +1075,14 @@ void xpath_t::op_t::find_values(value_t& context, scope_t * scope,
}
}
-bool xpath_t::op_t::test_value(value_t& context, scope_t * scope, int index)
+bool xpath_t::op_t::test_value(const value_t& context, scope_t * scope, int index)
{
xpath_t expr(compile(context, scope, true));
if (expr.ptr->kind != VALUE)
throw_(calc_error, "Predicate expression does not yield a constant value");
- switch (expr.ptr->as_value().type) {
+ switch (expr.ptr->as_value().type()) {
case value_t::INTEGER:
case value_t::AMOUNT:
return expr.ptr->as_value() == value_t((long)index + 1);
@@ -1117,7 +1117,7 @@ xpath_t::ptr_op_t xpath_t::op_t::defer_sequence(value_t::sequence_t& result_seq)
opp = &(*opp)->right();
}
- if ((*i).type != value_t::POINTER)
+ if (! (*i).is_type(value_t::POINTER))
*opp = wrap_value(*i);
else
#if 1
@@ -1133,7 +1133,7 @@ xpath_t::ptr_op_t xpath_t::op_t::defer_sequence(value_t::sequence_t& result_seq)
void xpath_t::op_t::append_value(value_t& val,
value_t::sequence_t& result_seq)
{
- if (val.type == value_t::SEQUENCE)
+ if (val.is_type(value_t::SEQUENCE))
std::for_each(val.as_sequence().begin(), val.as_sequence().end(),
bind(&value_t::sequence_t::push_back, ref(result_seq), _1));
else
@@ -1141,7 +1141,7 @@ void xpath_t::op_t::append_value(value_t& val,
}
xpath_t::ptr_op_t
-xpath_t::op_t::compile(value_t& context, scope_t * scope, bool resolve)
+xpath_t::op_t::compile(const value_t& context, scope_t * scope, bool resolve)
{
#if 0
try {
@@ -1156,7 +1156,7 @@ xpath_t::op_t::compile(value_t& context, scope_t * scope, bool resolve)
return wrap_value(context);
case document_t::PARENT:
- if (context.type != value_t::XML_NODE)
+ if (! context.is_type(value_t::XML_NODE))
throw_(compile_error, "Referencing parent node from a non-node value");
else if (context.as_xml_node()->parent())
return wrap_value(&*context.as_xml_node()->parent());
@@ -1164,13 +1164,13 @@ xpath_t::op_t::compile(value_t& context, scope_t * scope, bool resolve)
throw_(compile_error, "Referencing parent node from the root node");
case document_t::ROOT:
- if (context.type != value_t::XML_NODE)
+ if (! context.is_type(value_t::XML_NODE))
throw_(compile_error, "Referencing root node from a non-node value");
else
return wrap_value(&context.as_xml_node()->document());
case document_t::ALL: {
- if (context.type != value_t::XML_NODE)
+ if (! context.is_type(value_t::XML_NODE))
throw_(compile_error, "Referencing child nodes from a non-node value");
value_t::sequence_t nodes;
@@ -1240,7 +1240,7 @@ xpath_t::op_t::compile(value_t& context, scope_t * scope, bool resolve)
case ARG_INDEX:
if (scope && scope->kind == scope_t::ARGUMENT) {
- assert(scope->args.type == value_t::SEQUENCE);
+ assert(scope->args.is_type(value_t::SEQUENCE));
if (as_long() < scope->args.as_sequence().size())
return wrap_value(scope->args.as_sequence()[as_long()]);
else
@@ -1617,7 +1617,7 @@ xpath_t::op_t::compile(value_t& context, scope_t * scope, bool resolve)
value_t::sequence_t result_seq;
// jww (2006-09-24): What about when nothing is found?
- switch (lexpr.ptr->as_value().type) {
+ switch (lexpr.ptr->as_value().type()) {
case value_t::XML_NODE: {
value_t& value(lexpr.ptr->as_value());
function_scope_t xpath_fscope(*value.as_xml_node(), 0, 1, scope);
@@ -1632,14 +1632,14 @@ xpath_t::op_t::compile(value_t& context, scope_t * scope, bool resolve)
}
case value_t::SEQUENCE: {
- value_t::sequence_t& seq(lexpr.ptr->as_value().as_sequence());
+ const value_t::sequence_t& seq(lexpr.ptr->as_value().as_sequence());
int index = 0;
- for (value_t::sequence_t::iterator i = seq.begin();
+ for (value_t::sequence_t::const_iterator i = seq.begin();
i != seq.end();
i++, index++) {
- assert((*i).type != value_t::SEQUENCE);
- if ((*i).type != value_t::XML_NODE)
+ assert(! (*i).is_type(value_t::SEQUENCE));
+ if (! (*i).is_type(value_t::XML_NODE))
throw_(compile_error, "Attempting to apply path selection "
"to non-node(s)");
@@ -1772,7 +1772,7 @@ bool xpath_t::op_t::print(std::ostream& out,
switch (kind) {
case VALUE: {
const value_t& value(as_value());
- switch (value.type) {
+ switch (value.type()) {
case value_t::BOOLEAN:
if (value)
out << "1";
diff --git a/src/xpath.h b/src/xpath.h
index 485b5585..6d2ffcd2 100644
--- a/src/xpath.h
+++ b/src/xpath.h
@@ -99,18 +99,18 @@ public:
class function_scope_t : public scope_t
{
- node_t& node;
- std::size_t index;
- std::size_t size;
+ const node_t& node;
+ std::size_t index;
+ std::size_t size;
public:
function_scope_t(const value_t::sequence_t& _sequence,
- node_t& _node, std::size_t _index,
+ const node_t& _node, std::size_t _index,
scope_t * _parent = NULL)
: scope_t(_parent, STATIC), node(_node), index(_index),
size(_sequence.size()) {}
- function_scope_t(node_t& _node, std::size_t _index,
+ function_scope_t(const node_t& _node, std::size_t _index,
std::size_t _size, scope_t * _parent = NULL)
: scope_t(_parent, STATIC), node(_node), index(_index),
size(_size) {}
@@ -490,6 +490,12 @@ public:
return const_cast<op_t *>(this)->as_op();
}
+ void acquire() const {
+ DEBUG("ledger.xpath.memory",
+ "Acquiring " << this << ", refc now " << refc + 1);
+ assert(refc >= 0);
+ refc++;
+ }
void release() const {
DEBUG("ledger.xpath.memory",
"Releasing " << this << ", refc now " << refc - 1);
@@ -497,12 +503,6 @@ public:
if (--refc == 0)
checked_delete(this);
}
- void acquire() {
- DEBUG("ledger.xpath.memory",
- "Acquiring " << this << ", refc now " << refc + 1);
- assert(refc >= 0);
- refc++;
- }
ptr_op_t& left() {
return left_;
@@ -533,11 +533,11 @@ public:
ptr_op_t right = NULL);
ptr_op_t copy(ptr_op_t left = NULL, ptr_op_t right = NULL) const;
- ptr_op_t compile(value_t& context, scope_t * scope, bool resolve = false);
+ ptr_op_t compile(const value_t& context, scope_t * scope, bool resolve = false);
- void find_values(value_t& context, scope_t * scope,
+ void find_values(const value_t& context, scope_t * scope,
value_t::sequence_t& result_seq, bool recursive);
- bool test_value(value_t& context, scope_t * scope, int index = 0);
+ bool test_value(const value_t& context, scope_t * scope, int index = 0);
void append_value(value_t& value, value_t::sequence_t& result_seq);