HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Basics C++ Constructs

Evaluating Parameters

Custom PDG node definitions can evaluate parameters directly within a node callback implementation. At minimum, parameter evaluation only requires the name of the parameter, howevever it's also possible to specify a parameter index, a multiparm index, and a work item to use for expression evaluation.

The PDG_NodeCallback class supports evaluating parameters as strings, integers, floats, booleans, and as a generic templated function. String parameters can also be evaluated as a "raw" string, without variable or backtick expansion. All of the evaluation methods take the same parameters, return a value based on the evaluation type, and have a suffix in the name that identifies the evaluation type. For example, PDG_NodeCallback::evaluateS() or PDG_NodeCallback::evaluateB().

Failures during parameter evaluation are stashed on the thread-local evaluation context, and cause the callback to fail once it finishes executing. It's also possible to call the generic PDG_NodeCallback::evaluate() method, which returns a boolean value indicating whether the parameter evaluated directly and returns its evaluation output via a reference parameter. This variant of parameter evaluation is more verbose, but allows for more immediate handling for failures during evaluation.

For example:

PDG_CustomPartitioner::onPartition(
const PDG_WorkItemArray& work_items,
const PDG_WorkItem* target)
{
// Evaluate a parameter named "attribute", defaults to index=0 and does
// not use a work item.
UT_StringHolder attrib_name = evaluateS("attribute");
for (auto&& work_item : work_items)
{
// Evaluate a parameter called "filter", which should be treated as a
// boolean value. Specifies a work item, so the parameter can use an
// expression that varies per-work item. For example, the parameter
// may have an expression with an @attrib reference or a pdgattrib(..)
// function call.
bool filter = evaluateB("filter", work_item);
if (!filter)
continue;
// Evaluate a parameter named "partitiontype", and interpret it as an
// enum value. The generic templated evaluation method can be used to
// force an evaluation result to any tyme, assuming a valid cast exists
PartitionType type = evaluateT<PartitionType>("partitiontype", work_item);
// ... perform logic with evaluated parameter results ...
}
}

Accessing Attributes

The main way that data flows through a PDG graph is via work item attributes. Internally, a work item's command field, output files and environment variables are also implemented as attributes, but can also be accessed with higher level API.

The attributes on a work item are automatically inherited from their parent, or from their dependencies in the case of a partition. Attributes are stored in a PDG_AttributeMap owned by the work item. The attribute map has high level functions for setting and getting attribute values:

auto&& attributes = work_item->attributes();
// Set a float value named "size" to 5 at index 0, and created the attribute if
// it does not exist
attributes.setValue<PDG_AttributeFloat>("size", 5.0, 0, true);
// Set an integer value named "type" to 6 at index 0, but only if it already
// exists. If it does not, an error code is returned
auto err = attributes.setValue<PDG_AttributeInteger>("type", 6, 0, false);
if (err == PDG_AttributeRef::eErrorNotFound)
work_item->addError("Attribute named 'type' is missing");
// Read a string attribute value named "name" at index 2, and log an error if
// the attribute isn't found
if (!attributes.value<PDG_AttributeString>(name, "name", 2))
work_item->addError("Attribute named 'name' is missing");

It's also possible to use the lower-level PDG_AttributeRef API to create a reference to a specific attribute on a work item. This is useful when performing multiple operations on the same attribute in bulk. The API also offers other utility methods, like converting values to strings.

The PDG_AttributRef behaves like a smart pointer – it has methods of its own, but also provides a way to access the underlying attribute object using the -> indirection operator.

// Create a read-only reference to a string attribute called "name", and check
// if the reference is valid
auto&& attrib = work_item->attributes().refRO<PDG_AttributeString>("name");
if (!attrib)
return false;
// Print the third value in the attribute -- here we access the underyling
// string attribute.
UTformat("name[3] = {}\n", attrib->value(3));
// Convert the attribute to a space-separated list of string values, using
// a utility method on the reference itself
attrib.asStringValues(buffer);
UTformat("name[{}] = {}\n", attrib.size(), buffer);

It's also possible to create a read reference to an attribute without knowing the actual type. This limits the operations that can be performed, for example it's not possible to look up values, however it is possible to call generic methods from the reference itself. For example, this can be useful when writing a comparator function for sorting that operates on arbitrary data.

// Create a read reference to an arbitrary attribute and check that it's valid
auto&& attrib = work_item->attributes.refRO("attrib");
if (!attrib)
return false;
// Convert the value in the attribute at index=0 to a number
attrib.asNumber(value, 0)
UTformat("attrib[0] = {}\n", value);

Writing to an attribute can also be done using the reference API, by acquiring a read-write reference:

// Create an RW reference to an attribute named "scale", and create it if
// the attribute does not exist
auto&& attrib = work_item->attributes().refRW<PDG_AttributeInteger>("scale", true);
// We can use the validate helper method to error check the attrib ref and
/ report the appropriate errors on a particular node all in one operation.
if (!attrib.validate(myNode))
return false;
// Set the value of the new attribute at a particular index, on the underlying
// attribute itself
attrib->setValue(10, 0);
// A read-write reference has all of the functionality of a read only reference,
// and can therefore also be used to read values
UTformat("scale[0] = {}\n", attrib->value(0));