Qore Programming Language  0.9.4.6
Qore Data

Qore Data

All data value in Qore (and, in fact, all elements of Qore parse trees) are descended from AbstractQoreNode.

The following are the basic data types in Qore, implemented as C++ classes descended from AbstractQoreNode, and their type codes, accessed via AbstractQoreNode::getType():

Additionally, the following classes are exposed in the library:

See also
node_types.h for a complete list of all type codes.

The fastest way to directly access data of a specific type is to use the non-virtual function AbstractQoreNode::getType() and then to do a reinterpret_cast to the appropriate type as follows:

if (node->getType() == NT_DATE) {
DateTimeNode *dt = reinterpret_cast<DateTimeNode *>(node);
// .. do something with dt
}

This is faster than using dynamic_cast<> as follows (which is also a perfectly legal method for getting a pointer/testing the data type as well, just a little slower due to the dynamic_cast<>):

DateTimeNode *dt = dynamic_cast<DateTimeNode *>(node);
if (dt) {
// do something with dt...
}

Simple Value Types: QoreBigIntNode, QoreFloatNode, QoreStringNode, DateTimeNode, BinaryNode

The QoreBigIntNode (NT_INT), QoreFloatNode (NT_FLOAT), QoreStringNode (NT_STRING), DateTimeNode (NT_DATE), and BinaryNode (NT_BINARY) classes are reference counted and can only be dynamically allocated.

They are all descendents of SimpleQoreNode, meaning that dereferencing their objects cannot cause a Qore-language exception to be thrown (hence all support the SimpleQoreNode::deref() function), therefore the SimpleRefHolder class can be used to manage temporary references to objects of these types.

For example:

{
// here getQoreBigIntNode() returns a QoreBigIntNode value with an incremented reference count
SimpleRefHolder<QoreBigIntNode> qint(getQoreBigIntNode());
printf("the result is: %lld\n", qint->val);
// when qint goes out of scope, the reference count is decremented by calling SimpleQoreNode::deref()
}

Unique Value Types: QoreBoolNode, QoreNullNode, QoreNothingNode

QoreBoolNode (NT_BOOLEAN), QoreNullNode (NT_NULL), and QoreNothingNode (NT_NOTHING, but also equivalent to a 0 pointer, see the note below) are special classes in that they may not be directly instantiated with the new operator. They are all represented by single non-reference-counted objects managed directly by the Qore library. Each of these classes represents a type that has only one value, therefore as a memory and performance optimization, reference counting is disabled for their objects. Actually in the case of QoreBoolNode the subclasses QoreBoolTrueNode and QoreBoolFalseNode have actual instantiations.

For the QoreBoolNode class, you can use these objects by referring to the global True and False objects, or by calling get_bool_node() as follows in the example function:

static AbstractQoreNode *f_convert_first_argument_to_bool(const QoreListNode *params, ExceptionSink *xsink)
{
const AbstractQoreNode *p = get_param(params, 0);
return get_bool_node(p ? p->getAsBool() : false);
}

Or, some even simpler functions:

static AbstractQoreNode *f_return_true(const QoreListNode *params, ExceptionSink *xsink)
{
return &True; // QoreBoolNode objects are not reference counted (reference counting operations are ignored)
}
static AbstractQoreNode *f_return_false(const QoreListNode *params, ExceptionSink *xsink)
{
return &False; // QoreBoolNode objects are not reference counted (reference counting operations are ignored)
}

Similarly, for QoreNullNode there is the global Null object or the inline function null() that returns a pointer to this object. The inline function is_null() can be used to test for a Qore SQL Null value.

QoreNothingNode has the gobal Nothing object and the inline function nothing() that returns a pointer to it as well.

Note
that in Qore a C++ null pointer (0) is the same as NOTHING, therefore the inline function is_nothing() should always be used to test for NOTHING. Therefore the following code is incorrect:
// get_qore_value() returns an "AbstractQoreNode *"
AbstractQoreNode *p = get_qore_value();
if (!p) { // incorrect! NOTHING in Qore can be represented by a 0 or a pointer to the Nothing value
}

The code should look like this instead:

// get_qore_value() returns an "AbstractQoreNode *"
AbstractQoreNode *p = get_qore_value();
if (is_nothing(p)) { // correct test for nothing
}

Container Value Types: QoreHashNode, QoreListNode, QoreObject

The QoreHashNode (NT_HASH), QoreListNode (NT_LIST), and QoreObject (NT_OBJECT) classes define container types in Qore. QoreObject objects in particular could throw an exception when dereferenced (if the object goes out of scope and its destructor is run, the destructor could throw an exception). Because container types can hold any type, when they are deferenced it could cause a QoreObject to go out of scope, and therefore the possibility that a Qore-language exception could be thrown must be taken into consideration. Therefore, to dereference these objects a pointer to an ExceptionSink object must be passed to AbstractQoreNode::deref().

The ReferenceHolder class can be used to manage temporary reference counts as follows:

{
// here a QoreHashNode value is returned with an incremented reference count
// note that xsink must be "ExceptionSink *"
ReferenceHolder<QoreHashNode> qhash(getQoreHashNode(), xsink);
printf("there are %ld elements in the hash\n", qhash->size());
// when qhash goes out of scope, the reference count is decremented
}

Object Value Type: QoreObject

QoreObject objects have node type NT_OBJECT as returned by AbstractQoreNode::getType().

QoreObject is special in that the implementation for objects in Qore mirrors that of Java, in that objects are pased by reference when used as function or method arguments, unlike other types. However, like Java, the reference to the object is passed, and not the variable, so, while an object passed as an argument to a function can be modified by that function (modifications are made to the original object), in order to write a swap method, for example, you would need to pass the variables by reference (or the lvalue expression by reference, as the case may be) to the swap function. Unlike Java, Qore does support passing arguments by reference.

Handling Reference Arguments: ReferenceNode and ReferenceHelper

Handling lvalue references is more complicated, as access to global variables and object member references must be made under the appropriate thread locks. However the ReferenceHelper class makes access to lvalue references much easier and takes care of all the locking and access to the lvalue expression. With the ReferenceHelper class you can get the type of the lvalue expression's value, get a pointer to a node with a reference count of 1 for in-place modification, or assign a new value to the lvalue.

Here is an example of the use of ReferenceHelper:

static AbstractQoreNode *f_chomp(const QoreListNode *params, ExceptionSink *xsink)
{
const AbstractQoreNode *p = get_param(params, 0);
if (!p)
return 0;
qore_type_t ptype = p->getType();
// ... some code not relevant to this example removed
// note that the function test_reference_param() can be used
// to test for a reference argument directly
if (ptype != NT_REFERENCE)
return 0;
const ReferenceNode *r = reinterpret_cast<const ReferenceNode *>(p);
// ReferenceHelper will take care of locking any objects that need to
// be locked for accessing the variable (if necessary). The locks
// are released when the ReferenceHelper object goes out of scope
AutoVLock vl(xsink);
ReferenceHelper ref(r, vl, xsink);
if (!ref || ref.getType() != NT_STRING)
return 0;
QoreStringNode *str = reinterpret_cast<QoreStringNode *>(ref.getUnique(xsink));
if (*xsink)
return 0;
str->chomp();
return str->refSelf();
}