Modified value_t to use copy-on-write semantics.
This commit is contained in:
parent
d89f6e1c44
commit
5282260471
7 changed files with 1186 additions and 1110 deletions
|
|
@ -153,7 +153,7 @@ bool entry_base_t::finalize()
|
||||||
// account if one has been set.
|
// account if one has been set.
|
||||||
|
|
||||||
if (journal && journal->basket && transactions.size() == 1) {
|
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);
|
transaction_t * nxact = new transaction_t(journal->basket);
|
||||||
// The amount doesn't need to be set because the code below will
|
// The amount doesn't need to be set because the code below will
|
||||||
// balance this transaction against the other.
|
// 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
|
// determine its price by dividing the unit count into the value of
|
||||||
// the balance. This is done for the last eligible commodity.
|
// 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) {
|
balance.as_balance().amounts.size() == 2) {
|
||||||
transactions_list::const_iterator x = transactions.begin();
|
transactions_list::const_iterator x = transactions.begin();
|
||||||
assert((*x)->amount);
|
assert((*x)->amount);
|
||||||
|
|
@ -227,8 +227,8 @@ bool entry_base_t::finalize()
|
||||||
// commodities are involved, multiple transactions will be
|
// commodities are involved, multiple transactions will be
|
||||||
// generated to balance them all.
|
// generated to balance them all.
|
||||||
|
|
||||||
balance_t * bal = NULL;
|
const balance_t * bal = NULL;
|
||||||
switch (balance.type) {
|
switch (balance.type()) {
|
||||||
case value_t::BALANCE_PAIR:
|
case value_t::BALANCE_PAIR:
|
||||||
bal = &balance.as_balance_pair().quantity;
|
bal = &balance.as_balance_pair().quantity;
|
||||||
// fall through...
|
// fall through...
|
||||||
|
|
|
||||||
|
|
@ -180,10 +180,10 @@ void python_interpreter_t::functor_t::operator()(value_t& result,
|
||||||
if (! PyCallable_Check(func.ptr())) {
|
if (! PyCallable_Check(func.ptr())) {
|
||||||
result = static_cast<const value_t&>(extract<value_t>(func.ptr()));
|
result = static_cast<const value_t&>(extract<value_t>(func.ptr()));
|
||||||
} else {
|
} else {
|
||||||
assert(locals->args.type == value_t::SEQUENCE);
|
assert(locals->args.is_type(value_t::SEQUENCE));
|
||||||
if (locals->args.as_sequence().size() > 0) {
|
if (locals->args.as_sequence().size() > 0) {
|
||||||
list arglist;
|
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().begin();
|
||||||
i != locals->args.as_sequence().end();
|
i != locals->args.as_sequence().end();
|
||||||
i++)
|
i++)
|
||||||
|
|
@ -218,10 +218,10 @@ void python_interpreter_t::lambda_t::operator()(value_t& result,
|
||||||
xml::xpath_t::scope_t * locals)
|
xml::xpath_t::scope_t * locals)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
assert(locals->args.type == value_t::SEQUENCE);
|
assert(locals->args.is_type(value_t::SEQUENCE));
|
||||||
assert(locals->args.as_sequence().size() == 1);
|
assert(locals->args.as_sequence().size() == 1);
|
||||||
value_t item = locals->args[0];
|
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());
|
result = call<value_t>(func.ptr(), item.as_xml_node());
|
||||||
}
|
}
|
||||||
catch (const error_already_set&) {
|
catch (const error_already_set&) {
|
||||||
|
|
|
||||||
|
|
@ -253,12 +253,14 @@ xml::xpath_t::ptr_op_t session_t::lookup(const string& name)
|
||||||
static void initialize()
|
static void initialize()
|
||||||
{
|
{
|
||||||
amount_t::initialize();
|
amount_t::initialize();
|
||||||
|
value_t::initialize();
|
||||||
xml::xpath_t::initialize();
|
xml::xpath_t::initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void shutdown()
|
static void shutdown()
|
||||||
{
|
{
|
||||||
xml::xpath_t::shutdown();
|
xml::xpath_t::shutdown();
|
||||||
|
value_t::shutdown();
|
||||||
amount_t::shutdown();
|
amount_t::shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
1807
src/value.cc
1807
src/value.cc
File diff suppressed because it is too large
Load diff
409
src/value.h
409
src/value.h
|
|
@ -58,9 +58,7 @@ class value_t
|
||||||
ordered_field_operators<value_t, unsigned long,
|
ordered_field_operators<value_t, unsigned long,
|
||||||
ordered_field_operators<value_t, long> > > > > > >
|
ordered_field_operators<value_t, long> > > > > > >
|
||||||
{
|
{
|
||||||
char data[sizeof(balance_pair_t)];
|
public:
|
||||||
|
|
||||||
public:
|
|
||||||
typedef std::vector<value_t> sequence_t;
|
typedef std::vector<value_t> sequence_t;
|
||||||
|
|
||||||
enum type_t {
|
enum type_t {
|
||||||
|
|
@ -75,236 +73,366 @@ class value_t
|
||||||
SEQUENCE,
|
SEQUENCE,
|
||||||
XML_NODE,
|
XML_NODE,
|
||||||
POINTER
|
POINTER
|
||||||
} type;
|
};
|
||||||
|
|
||||||
value_t() : type(VOID) {
|
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();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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, "");
|
TRACE_CTOR(value_t, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
value_t(const value_t& val) : type(VOID) {
|
value_t(const value_t& val) {
|
||||||
TRACE_CTOR(value_t, "copy");
|
TRACE_CTOR(value_t, "copy");
|
||||||
*this = val;
|
*this = val;
|
||||||
}
|
}
|
||||||
value_t(const bool val) {
|
value_t(const bool val) {
|
||||||
TRACE_CTOR(value_t, "const bool");
|
TRACE_CTOR(value_t, "const bool");
|
||||||
type = BOOLEAN;
|
set_boolean(val);
|
||||||
as_boolean() = val;
|
|
||||||
}
|
}
|
||||||
value_t(const long val) {
|
value_t(const long val) {
|
||||||
TRACE_CTOR(value_t, "const long");
|
TRACE_CTOR(value_t, "const long");
|
||||||
type = INTEGER;
|
set_long(val);
|
||||||
as_long() = val;
|
|
||||||
}
|
}
|
||||||
value_t(const moment_t val) {
|
value_t(const moment_t val) {
|
||||||
TRACE_CTOR(value_t, "const moment_t");
|
TRACE_CTOR(value_t, "const moment_t");
|
||||||
type = DATETIME;
|
set_datetime(val);
|
||||||
new((moment_t *) data) moment_t(val);
|
|
||||||
}
|
}
|
||||||
value_t(const double val) {
|
value_t(const double val) {
|
||||||
TRACE_CTOR(value_t, "const double");
|
TRACE_CTOR(value_t, "const double");
|
||||||
type = AMOUNT;
|
set_amount(val);
|
||||||
new((amount_t *) data) amount_t(val);
|
|
||||||
}
|
}
|
||||||
value_t(const unsigned long val) {
|
value_t(const unsigned long val) {
|
||||||
TRACE_CTOR(value_t, "const unsigned long");
|
TRACE_CTOR(value_t, "const unsigned long");
|
||||||
type = AMOUNT;
|
set_amount(val);
|
||||||
new((amount_t *) data) amount_t(val);
|
|
||||||
}
|
}
|
||||||
value_t(const string& val, bool literal = false) {
|
value_t(const string& val, bool literal = false) {
|
||||||
TRACE_CTOR(value_t, "const string&, bool");
|
TRACE_CTOR(value_t, "const string&, bool");
|
||||||
if (literal) {
|
if (literal)
|
||||||
type = STRING;
|
set_string(val);
|
||||||
new((string *) data) string(val);
|
else
|
||||||
} else {
|
set_amount(val);
|
||||||
type = AMOUNT;
|
|
||||||
new((amount_t *) data) amount_t(val);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
value_t(const char * val, bool literal = false) {
|
value_t(const char * val, bool literal = false) {
|
||||||
TRACE_CTOR(value_t, "const char *");
|
TRACE_CTOR(value_t, "const char *");
|
||||||
if (literal) {
|
if (literal)
|
||||||
type = STRING;
|
set_string(val);
|
||||||
new((string *) data) string(val);
|
else
|
||||||
} else {
|
set_amount(val);
|
||||||
type = AMOUNT;
|
|
||||||
new((amount_t *) data) amount_t(val);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
value_t(const amount_t& val) {
|
value_t(const amount_t& val) {
|
||||||
TRACE_CTOR(value_t, "const amount_t&");
|
TRACE_CTOR(value_t, "const amount_t&");
|
||||||
type = AMOUNT;
|
set_amount(val);
|
||||||
new((amount_t *)data) amount_t(val);
|
|
||||||
}
|
}
|
||||||
value_t(const balance_t& val) : type(VOID) {
|
value_t(const balance_t& val) {
|
||||||
TRACE_CTOR(value_t, "const balance_t&");
|
TRACE_CTOR(value_t, "const balance_t&");
|
||||||
type = BALANCE;
|
set_balance(val);
|
||||||
new((balance_t *)data) balance_t(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&");
|
TRACE_CTOR(value_t, "const balance_pair_t&");
|
||||||
type = BALANCE_PAIR;
|
set_balance_pair(val);
|
||||||
new((balance_pair_t *)data) balance_pair_t(val);
|
|
||||||
}
|
}
|
||||||
value_t(const sequence_t& val) {
|
value_t(const sequence_t& val) {
|
||||||
TRACE_CTOR(value_t, "const sequence_t&");
|
TRACE_CTOR(value_t, "const sequence_t&");
|
||||||
type = SEQUENCE;
|
set_sequence(val);
|
||||||
new((sequence_t *)data) sequence_t(val);
|
|
||||||
}
|
}
|
||||||
value_t(xml::node_t * xml_node) {
|
value_t(xml::node_t * xml_node) {
|
||||||
TRACE_CTOR(value_t, "xml::node_t *");
|
TRACE_CTOR(value_t, "xml::node_t *");
|
||||||
type = XML_NODE;
|
set_xml_node(xml_node);
|
||||||
as_xml_node() = xml_node;
|
|
||||||
}
|
}
|
||||||
value_t(void * item) {
|
value_t(void * item) {
|
||||||
TRACE_CTOR(value_t, "void *");
|
TRACE_CTOR(value_t, "void *");
|
||||||
type = POINTER;
|
set_pointer(item);
|
||||||
as_pointer() = item;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~value_t() {
|
~value_t() {
|
||||||
TRACE_DTOR(value_t);
|
TRACE_DTOR(value_t);
|
||||||
destroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy();
|
|
||||||
value_t simplify() const {
|
|
||||||
value_t temp = *this;
|
|
||||||
temp.in_place_simplify();
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
void in_place_simplify();
|
|
||||||
|
|
||||||
value_t& operator=(const value_t& val);
|
value_t& operator=(const value_t& val);
|
||||||
|
|
||||||
value_t& set_string(const string& str = "") {
|
/**
|
||||||
if (type != STRING) {
|
* _dup() makes a private copy of the current value so that it can
|
||||||
destroy();
|
* subsequently be modified.
|
||||||
type = STRING;
|
*
|
||||||
new((string *) data) string(str);
|
* _clear() removes our pointer to the current value and initializes
|
||||||
} else {
|
* a new value for things to be stored in.
|
||||||
as_string() = str;
|
*/
|
||||||
}
|
void _dup() {
|
||||||
return *this;
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
operator bool() const;
|
||||||
|
|
||||||
|
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 {
|
bool is_boolean() const {
|
||||||
return type == BOOLEAN;
|
return is_type(BOOLEAN);
|
||||||
}
|
}
|
||||||
bool& as_boolean() {
|
bool& as_boolean_lval() {
|
||||||
assert(type == BOOLEAN);
|
assert(is_boolean());
|
||||||
return *(bool *) data;
|
_dup();
|
||||||
|
return *(bool *) storage->data;
|
||||||
}
|
}
|
||||||
const bool& as_boolean() const {
|
const bool& as_boolean() const {
|
||||||
assert(type == BOOLEAN);
|
assert(is_boolean());
|
||||||
return *(bool *) data;
|
return *(bool *) storage->data;
|
||||||
|
}
|
||||||
|
void set_boolean(const bool val) {
|
||||||
|
set_type(BOOLEAN);
|
||||||
|
storage = val ? true_value : false_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_long() const {
|
bool is_long() const {
|
||||||
return type == INTEGER;
|
return is_type(INTEGER);
|
||||||
}
|
}
|
||||||
long& as_long() {
|
long& as_long_lval() {
|
||||||
assert(type == INTEGER);
|
assert(is_long());
|
||||||
return *(long *) data;
|
_dup();
|
||||||
|
return *(long *) storage->data;
|
||||||
}
|
}
|
||||||
const long& as_long() const {
|
const long& as_long() const {
|
||||||
assert(type == INTEGER);
|
assert(is_long());
|
||||||
return *(long *) data;
|
return *(long *) storage->data;
|
||||||
|
}
|
||||||
|
void set_long(const long val) {
|
||||||
|
set_type(INTEGER);
|
||||||
|
*(long *) storage->data = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_datetime() const {
|
bool is_datetime() const {
|
||||||
return type == DATETIME;
|
return is_type(DATETIME);
|
||||||
}
|
}
|
||||||
moment_t& as_datetime() {
|
moment_t& as_datetime_lval() {
|
||||||
assert(type == DATETIME);
|
assert(is_datetime());
|
||||||
return *(moment_t *) data;
|
_dup();
|
||||||
|
return *(moment_t *) storage->data;
|
||||||
}
|
}
|
||||||
const moment_t& as_datetime() const {
|
const moment_t& as_datetime() const {
|
||||||
assert(type == DATETIME);
|
assert(is_datetime());
|
||||||
return *(moment_t *) data;
|
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 {
|
bool is_amount() const {
|
||||||
return type == AMOUNT;
|
return is_type(AMOUNT);
|
||||||
}
|
}
|
||||||
amount_t& as_amount() {
|
amount_t& as_amount_lval() {
|
||||||
assert(type == AMOUNT);
|
assert(is_amount());
|
||||||
return *(amount_t *) data;
|
_dup();
|
||||||
|
return *(amount_t *) storage->data;
|
||||||
}
|
}
|
||||||
const amount_t& as_amount() const {
|
const amount_t& as_amount() const {
|
||||||
assert(type == AMOUNT);
|
assert(is_amount());
|
||||||
return *(amount_t *) data;
|
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 {
|
bool is_balance() const {
|
||||||
return type == BALANCE;
|
return is_type(BALANCE);
|
||||||
}
|
}
|
||||||
balance_t& as_balance() {
|
balance_t& as_balance_lval() {
|
||||||
assert(type == BALANCE);
|
assert(is_balance());
|
||||||
return *(balance_t *) data;
|
_dup();
|
||||||
|
return *(balance_t *) storage->data;
|
||||||
}
|
}
|
||||||
const balance_t& as_balance() const {
|
const balance_t& as_balance() const {
|
||||||
assert(type == BALANCE);
|
assert(is_balance());
|
||||||
return *(balance_t *) data;
|
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 {
|
bool is_balance_pair() const {
|
||||||
return type == BALANCE_PAIR;
|
return is_type(BALANCE_PAIR);
|
||||||
}
|
}
|
||||||
balance_pair_t& as_balance_pair() {
|
balance_pair_t& as_balance_pair_lval() {
|
||||||
assert(type == BALANCE_PAIR);
|
assert(is_balance_pair());
|
||||||
return *(balance_pair_t *) data;
|
_dup();
|
||||||
|
return *(balance_pair_t *) storage->data;
|
||||||
}
|
}
|
||||||
const balance_pair_t& as_balance_pair() const {
|
const balance_pair_t& as_balance_pair() const {
|
||||||
assert(type == BALANCE_PAIR);
|
assert(is_balance_pair());
|
||||||
return *(balance_pair_t *) data;
|
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 {
|
bool is_string() const {
|
||||||
return type == STRING;
|
return is_type(STRING);
|
||||||
}
|
}
|
||||||
string& as_string() {
|
string& as_string_lval() {
|
||||||
assert(type == STRING);
|
assert(is_string());
|
||||||
return *(string *) data;
|
_dup();
|
||||||
|
return *(string *) storage->data;
|
||||||
}
|
}
|
||||||
const string& as_string() const {
|
const string& as_string() const {
|
||||||
assert(type == STRING);
|
assert(is_string());
|
||||||
return *(string *) data;
|
return *(string *) storage->data;
|
||||||
|
}
|
||||||
|
void set_string(const string& val = "") {
|
||||||
|
set_type(STRING);
|
||||||
|
new((string *) storage->data) string(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_sequence() const {
|
bool is_sequence() const {
|
||||||
return type == SEQUENCE;
|
return is_type(SEQUENCE);
|
||||||
}
|
}
|
||||||
sequence_t& as_sequence() {
|
sequence_t& as_sequence_lval() {
|
||||||
assert(type == SEQUENCE);
|
assert(is_sequence());
|
||||||
return *(sequence_t *) data;
|
_dup();
|
||||||
|
return *(sequence_t *) storage->data;
|
||||||
}
|
}
|
||||||
const sequence_t& as_sequence() const {
|
const sequence_t& as_sequence() const {
|
||||||
assert(type == SEQUENCE);
|
assert(is_sequence());
|
||||||
return *(sequence_t *) data;
|
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 {
|
bool is_xml_node() const {
|
||||||
return type == XML_NODE;
|
return is_type(XML_NODE);
|
||||||
}
|
}
|
||||||
xml::node_t *& as_xml_node() {
|
xml::node_t *& as_xml_node_lval() {
|
||||||
assert(type == XML_NODE);
|
assert(is_xml_node());
|
||||||
return *(xml::node_t **) data;
|
_dup();
|
||||||
|
return *(xml::node_t **) storage->data;
|
||||||
}
|
}
|
||||||
xml::node_t * as_xml_node() const {
|
xml::node_t * as_xml_node() const {
|
||||||
assert(type == XML_NODE);
|
assert(is_xml_node());
|
||||||
return *(xml::node_t **) data;
|
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 {
|
bool is_pointer() const {
|
||||||
return type == POINTER;
|
return is_type(POINTER);
|
||||||
}
|
}
|
||||||
void *& as_pointer() {
|
void *& as_pointer_lval() {
|
||||||
assert(type == POINTER);
|
assert(is_pointer());
|
||||||
return *(void **) data;
|
_dup();
|
||||||
|
return *(void **) storage->data;
|
||||||
}
|
}
|
||||||
void * as_pointer() const {
|
void * as_pointer() const {
|
||||||
assert(type == POINTER);
|
assert(is_pointer());
|
||||||
return *(void **) data;
|
return *(void **) storage->data;
|
||||||
|
}
|
||||||
|
void set_pointer(void * val) {
|
||||||
|
set_type(POINTER);
|
||||||
|
*(void **) storage->data = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool to_boolean() const;
|
bool to_boolean() const;
|
||||||
|
|
@ -316,15 +444,25 @@ class value_t
|
||||||
string to_string() const;
|
string to_string() const;
|
||||||
sequence_t to_sequence() 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) {
|
value_t& operator[](const int index) {
|
||||||
|
return as_sequence_lval()[index];
|
||||||
|
}
|
||||||
|
const value_t& operator[](const int index) const {
|
||||||
return as_sequence()[index];
|
return as_sequence()[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_back(const value_t& val) {
|
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();
|
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;
|
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 {
|
string label(optional<type_t> the_type = none) const {
|
||||||
switch (the_type ? *the_type : type) {
|
switch (the_type ? *the_type : type()) {
|
||||||
case VOID:
|
case VOID:
|
||||||
return "an uninitialized value";
|
return "an uninitialized value";
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
|
|
@ -369,8 +509,6 @@ class value_t
|
||||||
return "<invalid>";
|
return "<invalid>";
|
||||||
}
|
}
|
||||||
|
|
||||||
operator bool() const;
|
|
||||||
|
|
||||||
value_t operator-() const {
|
value_t operator-() const {
|
||||||
return negate();
|
return negate();
|
||||||
}
|
}
|
||||||
|
|
@ -421,19 +559,6 @@ class value_t
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& out, const value_t& val);
|
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);
|
DECLARE_EXCEPTION(value_error);
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
|
||||||
34
src/xpath.cc
34
src/xpath.cc
|
|
@ -1050,7 +1050,7 @@ xpath_t::op_t::copy(ptr_op_t tleft, ptr_op_t tright) const
|
||||||
return node;
|
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,
|
value_t::sequence_t& result_seq,
|
||||||
bool recursive)
|
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);
|
append_value(expr.ptr->as_value(), result_seq);
|
||||||
|
|
||||||
if (recursive) {
|
if (recursive) {
|
||||||
if (context.type == value_t::XML_NODE) {
|
if (context.is_type(value_t::XML_NODE)) {
|
||||||
node_t * ptr = context.as_xml_node();
|
node_t * ptr = context.as_xml_node();
|
||||||
if (ptr->is_parent_node())
|
if (ptr->is_parent_node())
|
||||||
foreach (node_t * node, ptr->as_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));
|
xpath_t expr(compile(context, scope, true));
|
||||||
|
|
||||||
if (expr.ptr->kind != VALUE)
|
if (expr.ptr->kind != VALUE)
|
||||||
throw_(calc_error, "Predicate expression does not yield a constant 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::INTEGER:
|
||||||
case value_t::AMOUNT:
|
case value_t::AMOUNT:
|
||||||
return expr.ptr->as_value() == value_t((long)index + 1);
|
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();
|
opp = &(*opp)->right();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((*i).type != value_t::POINTER)
|
if (! (*i).is_type(value_t::POINTER))
|
||||||
*opp = wrap_value(*i);
|
*opp = wrap_value(*i);
|
||||||
else
|
else
|
||||||
#if 1
|
#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,
|
void xpath_t::op_t::append_value(value_t& val,
|
||||||
value_t::sequence_t& result_seq)
|
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(),
|
std::for_each(val.as_sequence().begin(), val.as_sequence().end(),
|
||||||
bind(&value_t::sequence_t::push_back, ref(result_seq), _1));
|
bind(&value_t::sequence_t::push_back, ref(result_seq), _1));
|
||||||
else
|
else
|
||||||
|
|
@ -1141,7 +1141,7 @@ void xpath_t::op_t::append_value(value_t& val,
|
||||||
}
|
}
|
||||||
|
|
||||||
xpath_t::ptr_op_t
|
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
|
#if 0
|
||||||
try {
|
try {
|
||||||
|
|
@ -1156,7 +1156,7 @@ xpath_t::op_t::compile(value_t& context, scope_t * scope, bool resolve)
|
||||||
return wrap_value(context);
|
return wrap_value(context);
|
||||||
|
|
||||||
case document_t::PARENT:
|
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");
|
throw_(compile_error, "Referencing parent node from a non-node value");
|
||||||
else if (context.as_xml_node()->parent())
|
else if (context.as_xml_node()->parent())
|
||||||
return wrap_value(&*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");
|
throw_(compile_error, "Referencing parent node from the root node");
|
||||||
|
|
||||||
case document_t::ROOT:
|
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");
|
throw_(compile_error, "Referencing root node from a non-node value");
|
||||||
else
|
else
|
||||||
return wrap_value(&context.as_xml_node()->document());
|
return wrap_value(&context.as_xml_node()->document());
|
||||||
|
|
||||||
case document_t::ALL: {
|
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");
|
throw_(compile_error, "Referencing child nodes from a non-node value");
|
||||||
|
|
||||||
value_t::sequence_t nodes;
|
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:
|
case ARG_INDEX:
|
||||||
if (scope && scope->kind == scope_t::ARGUMENT) {
|
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())
|
if (as_long() < scope->args.as_sequence().size())
|
||||||
return wrap_value(scope->args.as_sequence()[as_long()]);
|
return wrap_value(scope->args.as_sequence()[as_long()]);
|
||||||
else
|
else
|
||||||
|
|
@ -1617,7 +1617,7 @@ xpath_t::op_t::compile(value_t& context, scope_t * scope, bool resolve)
|
||||||
value_t::sequence_t result_seq;
|
value_t::sequence_t result_seq;
|
||||||
|
|
||||||
// jww (2006-09-24): What about when nothing is found?
|
// 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: {
|
case value_t::XML_NODE: {
|
||||||
value_t& value(lexpr.ptr->as_value());
|
value_t& value(lexpr.ptr->as_value());
|
||||||
function_scope_t xpath_fscope(*value.as_xml_node(), 0, 1, scope);
|
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: {
|
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;
|
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 != seq.end();
|
||||||
i++, index++) {
|
i++, index++) {
|
||||||
assert((*i).type != value_t::SEQUENCE);
|
assert(! (*i).is_type(value_t::SEQUENCE));
|
||||||
if ((*i).type != value_t::XML_NODE)
|
if (! (*i).is_type(value_t::XML_NODE))
|
||||||
throw_(compile_error, "Attempting to apply path selection "
|
throw_(compile_error, "Attempting to apply path selection "
|
||||||
"to non-node(s)");
|
"to non-node(s)");
|
||||||
|
|
||||||
|
|
@ -1772,7 +1772,7 @@ bool xpath_t::op_t::print(std::ostream& out,
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case VALUE: {
|
case VALUE: {
|
||||||
const value_t& value(as_value());
|
const value_t& value(as_value());
|
||||||
switch (value.type) {
|
switch (value.type()) {
|
||||||
case value_t::BOOLEAN:
|
case value_t::BOOLEAN:
|
||||||
if (value)
|
if (value)
|
||||||
out << "1";
|
out << "1";
|
||||||
|
|
|
||||||
28
src/xpath.h
28
src/xpath.h
|
|
@ -99,18 +99,18 @@ public:
|
||||||
|
|
||||||
class function_scope_t : public scope_t
|
class function_scope_t : public scope_t
|
||||||
{
|
{
|
||||||
node_t& node;
|
const node_t& node;
|
||||||
std::size_t index;
|
std::size_t index;
|
||||||
std::size_t size;
|
std::size_t size;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
function_scope_t(const value_t::sequence_t& _sequence,
|
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 = NULL)
|
||||||
: scope_t(_parent, STATIC), node(_node), index(_index),
|
: scope_t(_parent, STATIC), node(_node), index(_index),
|
||||||
size(_sequence.size()) {}
|
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)
|
std::size_t _size, scope_t * _parent = NULL)
|
||||||
: scope_t(_parent, STATIC), node(_node), index(_index),
|
: scope_t(_parent, STATIC), node(_node), index(_index),
|
||||||
size(_size) {}
|
size(_size) {}
|
||||||
|
|
@ -490,6 +490,12 @@ public:
|
||||||
return const_cast<op_t *>(this)->as_op();
|
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 {
|
void release() const {
|
||||||
DEBUG("ledger.xpath.memory",
|
DEBUG("ledger.xpath.memory",
|
||||||
"Releasing " << this << ", refc now " << refc - 1);
|
"Releasing " << this << ", refc now " << refc - 1);
|
||||||
|
|
@ -497,12 +503,6 @@ public:
|
||||||
if (--refc == 0)
|
if (--refc == 0)
|
||||||
checked_delete(this);
|
checked_delete(this);
|
||||||
}
|
}
|
||||||
void acquire() {
|
|
||||||
DEBUG("ledger.xpath.memory",
|
|
||||||
"Acquiring " << this << ", refc now " << refc + 1);
|
|
||||||
assert(refc >= 0);
|
|
||||||
refc++;
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr_op_t& left() {
|
ptr_op_t& left() {
|
||||||
return left_;
|
return left_;
|
||||||
|
|
@ -533,11 +533,11 @@ public:
|
||||||
ptr_op_t right = NULL);
|
ptr_op_t right = NULL);
|
||||||
|
|
||||||
ptr_op_t copy(ptr_op_t left = NULL, ptr_op_t right = NULL) const;
|
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);
|
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);
|
void append_value(value_t& value, value_t::sequence_t& result_seq);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue