Modified value_t to use copy-on-write semantics.

This commit is contained in:
John Wiegley 2007-05-16 05:37:26 +00:00
parent d89f6e1c44
commit 5282260471
7 changed files with 1186 additions and 1110 deletions

View file

@ -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...

View file

@ -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&) {

View file

@ -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();
} }

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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";

View file

@ -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);