diff options
author | John Wiegley <johnw@newartisans.com> | 2007-05-16 05:37:26 +0000 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2008-04-13 03:38:52 -0400 |
commit | 52822604713b73160ac497bc170eb45d9a594306 (patch) | |
tree | 867027ab9186c04e7ecb2f101247f16307116e86 | |
parent | d89f6e1c447fc5e7fcd0d6e5a236298323f9596e (diff) | |
download | fork-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.cc | 8 | ||||
-rw-r--r-- | src/pyinterp.cc | 8 | ||||
-rw-r--r-- | src/session.cc | 2 | ||||
-rw-r--r-- | src/value.cc | 817 | ||||
-rw-r--r-- | src/value.h | 407 | ||||
-rw-r--r-- | src/xpath.cc | 34 | ||||
-rw-r--r-- | src/xpath.h | 28 |
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); |