Class that provides code generation helper utilities.
More...

Detailed Description

Class that provides code generation helper utilities.

Parameters

Member Function Documentation

◆ headerPrologue()

Given an operator instance model, produces the prolog code for the
operator's header code generator template

Parameters
open/close icon Code:
click to view
# Number of lines of code in headerPrologue: 5
sub headerPrologue($;$)
{
my ($model, $includes) = @_;
SPL::CodeGenHelper::headerPrologueImpl($model, 1, $includes);
}

◆ headerEpilogue()

Given an operator instance model, produces the epilog code for the operator's
header code generator template

Parameters
open/close icon Code:
click to view
# Number of lines of code in headerEpilogue: 5
{
my ($model) = @_;
SPL::CodeGenHelper::headerEpilogueImpl($model, 1);
}

◆ implementationPrologue()

Given an operator instnce model, produces the prolog code for the operator's
implementation code generator template

Parameters
open/close icon Code:
click to view
# Number of lines of code in implementationPrologue: 5
{
my ($model) = @_;
SPL::CodeGenHelper::implementationPrologueImpl($model, 1);
}

◆ implementationEpilogue()

Given an operator instance model, produces the epilog code for the operator's
implementation code generator template

Parameters
open/close icon Code:
click to view
# Number of lines of code in implementationEpilogue: 5
{
my ($model) = @_;
SPL::CodeGenHelper::implementationEpilogueImpl($model, 1);
}

◆ hasSideEffectInAssignments()

Given an output port object, return true if any output assignment expression has
side effects, otherwise false. This can be used to pull output tuple initialization
out of a loop.

Parameters
Returns
1 if any output assignment has side effects, 0 otherwise

Example: For
- tuple type tuple<int8 a, int8 b>, and
- SPL output assignment fragment output S : a = x, b = y;
this function will return 0.

For
- SPL output assignment fragment output S : a = x++, b = statefulFunction(y);
this function will return 1.
open/close icon Code:
click to view
# Number of lines of code in hasSideEffectInAssignments: 10
{
my ($outputPort) = @_;
my $numAttrs = $outputPort->getNumberOfAttributes();
for (my $i = 0; $i < $numAttrs; ++$i) {
my $exp = $outputPort->getAttributeAt($i)->getAssignmentValue();
return 1 if $exp && $exp->hasSideEffects();
}
return 0;
}

◆ hasStreamAttributeInAssignments()

Given an output port object, return true if any output assignment expression contains an input
attribute within the expression. This can be used to pull output tuple initialization out of a loop

Parameters
Returns
1 if any output assignment contains an input attribute, 0 otherwise

Example: For
- tuple type tuple<int8 a, int8 b>, and
- SPL output assignment fragment output S : a = x, b = y;
this function will return 1 if x or y are input stream attributes, 0 if they are both
state variables.
open/close icon Code:
click to view
# Number of lines of code in hasStreamAttributeInAssignments: 10
{
my ($outputPort) = @_;
my $numAttrs = $outputPort->getNumberOfAttributes();
for (my $i = 0; $i < $numAttrs; ++$i) {
my $exp = $outputPort->getAttributeAt($i)->getAssignmentValue();
return 1 if $exp && $exp->hasStreamAttributes();
}
return 0;
}

◆ getOutputTupleCppInitializer()

Given an output port object, return the C++ expression which can be used to
initialize a tuple for the port with the output assignments.

Parameters
Returns
a string containing the expression to be used for initializing the
output tuple

Example: For
- tuple type tuple<int8 a, int8 b>, and
- SPL output assignment fragment output S : a = x, b = y;

this function will produce the following:
- $iport0.get_x(), $iport0.get_y()

This can be used as:
<br> my $assignments = SPL::CodeGen::getOutputTupleCppInitializer($outputPort);
<br> emitALine "OPort${index}Type otuple($assignments);";
<br>


If an output assignment uses a Custom Output Function, the result will contain a call
to a function of the same name. If this is not desired, the operator should walk the
assignments one at a time, examining each one to generate the desired code.
open/close icon Code:
click to view
# Number of lines of code in getOutputTupleCppInitializer: 16
{
my ($outputPort) = @_;
my $numAttrs = $outputPort->getNumberOfAttributes();
my $assignments = "";
for (my $i = 0; $i < $numAttrs; ++$i) {
my $exp = $outputPort->getAttributeAt($i)->getAssignmentValue();
if ($exp) {
$assignments .= SPL::CodeGenHelper::ensureValue(
$outputPort->getAttributeAt($i)->getSPLType(),
$exp->getCppExpression());
$assignments .= ", " if $i < $numAttrs-1;
}
}
return $assignments;
}

◆ getOutputTupleCppAssignments()

Given a tuple name and an output port object, return a C++ code segment which
can be used to assign an already initialized tuple for the port with the
output attribute assignments captured in the output port object.

Parameters
Returns
a string containing the statements to carry out the output
assignments

Example: For
- tuple type tuple<int8 a, int8 b>, and
- SPL output assignment fragment output S : a = x, b = y;

getOutputTupleCppAssignments('fred', $port) will produce the
following:
- fred.set_a($iport0.get_x()); fred.set_b($iport0.get_y());
open/close icon Code:
click to view
# Number of lines of code in getOutputTupleCppAssignments: 14
{
my ($tupleName, $outputPort) = @_;
my $numAttrs = $outputPort->getNumberOfAttributes();
my $assignments = "";
for (my $i = 0; $i < $numAttrs; ++$i) {
my $attr = $outputPort->getAttributeAt($i);
if($attr->hasAssignment()) {
my $exp = $attr->getAssignmentValue();
$assignments .= "$tupleName.set_" . $attr->getName() . "(" . $exp->getCppExpression() . "); ";
}
}
return $assignments;
}

◆ getOutputTupleCppAssignmentsWithSideEffects()

Given a tuple name and an output port object, return a C++ code segment which
can be used to assign an already initialized tuple for the port with the
output attribute assignments captured in the output port object.
This is the same as getOutputTupleCppAssignments except for the additional
sideEffects parameter which is used to specify whether we want assignments
which contain side effects on the RHS (or not).

Parameters
Returns
a string containing the statements to carry out the output
assignments

Example: For
- tuple type tuple<int8 a, int8 b>, and
- SPL output assignment fragment output S : a = x, b = y++;
- we only want assignment fragments which contain side effects

getOutputTupleCppAssignmentsWithSideEffects('fred', $port, 1) will produce the
following:
- fred.set_b($iport0.get_y());
open/close icon Code:
click to view
# Number of lines of code in getOutputTupleCppAssignmentsWithSideEffects: 21
{
my ($tupleName, $outputPort, $sideEffects) = @_;
my $numAttrs = $outputPort->getNumberOfAttributes();
my $assignments = "";
for (my $i = 0; $i < $numAttrs; ++$i) {
my $attr = $outputPort->getAttributeAt($i);
if($attr->hasAssignment()) {
my $exp = $attr->getAssignmentValue();
if ($exp->hasStreamAttributes() || $exp->hasSideEffects()) {
if ($sideEffects) {
$assignments .= "$tupleName.set_" . $attr->getName() . "(" . $exp->getCppExpression() . "); ";
}
}
elsif (!$sideEffects) {
$assignments .= "$tupleName.set_" . $attr->getName() . "(" . $exp->getCppExpression() . "); ";
}
}
}
return $assignments;
}

◆ getParameterCppTypes()

Given a parameter object, return a list of C++ types corresponding to the
expressions contained within the parameter. The resulting list can be used as
the types parameter in an emitClass call.

Parameters
Returns
list of types
open/close icon Code:
click to view
# Number of lines of code in getParameterCppTypes: 10
{
my ($param) = @_;
return undef if not defined ($param);
my @types;
for (my $i = 0; $i < $param->getNumberOfValues(); $i++) {
push @types, $param->getValueAt($i)->getCppType();
}
return @types;
}

◆ getParameterCppInitializer()

Given a parameter object, return a C++ expresion that can be used as the
constructor initializer for an object of type returned by an br>SPL::CodeGen::emitClassemitClass@endlinkcall.<br>@paramparamparameterobject<br>@returnstringtobeusedasaconstructorinitializeror\aundefifparam<br>isnotdefined<br><br>Example:For<br>-%SPLparameterassignmentfragment<tt>paramkey:a,sqrt(b);</tt><br><br>thisfunctionwillproducethefollowing:<br>-<tt>$iport0.get_a(),SPL:Functions::Math::sqrt($iport0.get_b())</tt><br>@htmlonly[block]<divid='codesection-getParameterCppInitializer'class='dynheaderclosed'style='cursor:pointer;'onclick='returntoggleVisibility(this)'><imgid='codesection-getParameterCppInitializer-trigger'src='closed.png'alt='open/closeicon'style='display:inline'/><b>Code:</b></div><divid='codesection-getParameterCppInitializer-summary'class='dyncontent'style='display:block;font-size:small;'>clicktoview</div><divid='codesection-getParameterCppInitializer-content'class='dyncontent'style='display:none;'>@endhtmlonly@code#NumberoflinesofcodeingetParameterCppInitializer:14subgetParameterCppInitializer($)my($param)=@_;returnundefifnotdefined($param);my$res="";for(my$i=0;$i<$param->getNumberOfValues();$i++)my$value=$param->getValueAt($i);if($value)$res.=$value->getCppExpression();$res.=","if$i<$param->getNumberOfValues()-1;return$res;@endcode@htmlonly[block]</div>@endhtmlonly

◆ adaptCppExpression()

Obtain the C++ expression adapted for the given tuple context, where the
references to input tuples are replaced with the names given by the tuples
parameter.

Parameters
Returns
a string with the adapted C++ expression

Example: Consider a Filter operator with a filter parameter that defines
a predicate over the input tuple attributes. Here is how one can use the
filter expression from within the code generator template:

<br> <%
<br> my $filterParam = $model->getParameterByName("filter");
<br> my $filterExpr = $filterParam->getValueAt(0)->getCppExpression();
<br> %>
<br><br> void MY_OPERATOR::process(Tuple & tuple, uint32_t port) {
<br> if (<%=SPL::CodeGen:adaptCppExpression($filterExpr, "tuple")%>) {
<br> ...
<br> }
<br> }
<br>

open/close icon Code:
click to view
# Number of lines of code in adaptCppExpression: 62
{
my ($cppExpr, @tuples) = @_;
my %quotes;
my @chars = split(//, $cppExpr);
my $inQuotes = 0;
my $opening = 0;
my $ending = 0;
my $numSlashes = 0;
for(my $i=0; $i<scalar(@chars); ++$i)
{
if($inQuotes) {
if($chars[$i] eq "\\") {
++$numSlashes;
} else {
if(($chars[$i] eq "\"") &&
($numSlashes % 2 == 0)) {
$ending = $i;
$quotes{$opening} = $ending;
$inQuotes = 0;
}
$numSlashes = 0;
}
} else {
if($chars[$i] eq '"') {
$opening = $i;
$quotes{$opening} = undef;
$inQuotes = 1;
}
}
}
my $newString;
my $lastPos=0;
while($cppExpr =~ m/(iport\$\d+)/g) {
my $p = length($`);
my $l = length($&);
$inQuotes = 0;
foreach my $b (keys %quotes) {
my $e = $quotes{$b};
if($p>$b && $p<$e)
{
$inQuotes = 1;
last;
}
}
unless($inQuotes) {
$newString .= substr($cppExpr, $lastPos, $p-$lastPos);
my $token = $&;
my ($index) = ($& =~ m/(\d+)$/);
if($index >= scalar(@tuples)) {
SPL::CodeGen::errorln(SPL::Msg::INCORRECT_NUMBER_OF_TUPLE_VARIABLE_NAMES);
return;
}
$newString .= "SPL::port_cast<IPort${index}Type>(" . $tuples[$index] . ")";
$lastPos=$p+$l;
}
}
$newString .= substr($cppExpr, $lastPos, length($cppExpr)-$lastPos);
return $newString;
}

◆ prefixLiteralsAndStatesInCppExpressions()

Obtain the C++ expression with all references to lit$[0-9]*, state$
and iport$[0-9]+History prefixed by the prefix parameter.

Parameters
Returns
a string with the prefixed C++ expression

Example: Consider operator with a helper class that needs to handle general C++ expressions. The
helper class will need to ensure that literals and state variable s(which are in the base operator class)
can be compiled in C++. If the helper class has a reference to the operator class in variable _oper,
then we can prefix "_oper." to all literals, and the C++ expression will be valid.
a predicate over the input tuple attributes. Here is how one can use the
C++ expression from a Helper class:

<br> <%
<br> my $param = $model->getParameterByName("param");
<br> my $expr = $param->getValueAt(0)->getCppExpression();
<br> %>
<br><br> class HelperClass {
<br> MY_OPERATOR_SCOPE::MY_OPERATOR& _oper;
<br> public:
<br> HelperClass(MY_OPERATOR_SCOPE::MY_OPERATOR& oper) : _oper(oper) {}
<br> void doSomething() {
<br> int value = <%=SPL::CodeGen::prefixLiteralsAndStatesInCppExpressions($expr, "_oper.")%>;
<br> }
<br> }
<br>

open/close icon Code:
click to view
# Number of lines of code in prefixLiteralsAndStatesInCppExpressions: 57
{
my ($cppExpr, $prefix) = @_;
my %quotes;
my @chars = split(//, $cppExpr);
my $inQuotes = 0;
my $opening = 0;
my $ending = 0;
my $numSlashes = 0;
for(my $i=0; $i<scalar(@chars); ++$i)
{
if($inQuotes) {
if($chars[$i] eq "\\") {
++$numSlashes;
} else {
if(($chars[$i] eq "\"") &&
($numSlashes % 2 == 0)) {
$ending = $i;
$quotes{$opening} = $ending;
$inQuotes = 0;
}
$numSlashes = 0;
}
} else {
if($chars[$i] eq '"') {
$opening = $i;
$quotes{$opening} = undef;
$inQuotes = 1;
}
}
}
my $newString;
my $lastPos=0;
while($cppExpr =~ m/(state\$)|(lit\$\d+)|(iport\$\d+History)/g) {
my $p = length($`);
my $l = length($&);
$inQuotes = 0;
foreach my $b (keys %quotes) {
my $e = $quotes{$b};
if($p>$b && $p<$e)
{
$inQuotes = 1;
last;
}
}
unless($inQuotes) {
$newString .= substr($cppExpr, $lastPos, $p-$lastPos);
my $token = $&;
$newString .= "$prefix$token";
$lastPos=$p+$l;
}
}
$newString .= substr($cppExpr, $lastPos, length($cppExpr)-$lastPos);
return $newString;
}

◆ extractPerlValue()

Obtain the Perl value from a C++ expression of a given SPL type.

Precondition
the C++ expression must contain a C++ literal
the type must belong to one of the following categories: integral, float,
decimal, string, boolean
Parameters
Returns
a Perl value, or undef if unsuccessful

Example: Consider a Filter operator with a filter parameter that defines
a predicate over the input tuple attributes. Here is how one can use the
filter expression from within the code generator template:

<br> # Assume that the 'count' parameter is a Constant expression and expression
<br> # rewrite is turned off for the parameter.
<br> <%
<br> my $count = $model->getParameterByName("count")->getValueAt(0);
<br> my $c = SPL::CodeGen::extractPerlValue($count->getCppExpression(), $count->getSPLType());
<br> if($c>4) { ... }
<br> %>
<br>

open/close icon Code:
click to view
# Number of lines of code in extractPerlValue: 54
{
my ($cppExpr, $splType) = @_;
# if we start with a '(' then we are an expression, not a literal
return undef if $cppExpr =~ m/^\(/;
my $value = $cppExpr;
$value =~ s/SPL::[^\(]*\(//;
$value =~ s/\)$//;
# Check for valid literals values, else return undef
my $fp="([-+]?((\\d*\\.?\\d+([eE][-+]?\\d+)?f?)|(NAN)|(INFINITY)))";
if ($value =~ m/^\s*([-+]?\d+)(LL)?U?\s*$/) {
$value = $1;
} else {
return undef;
}
} elsif(SPL::CodeGen::Type::isFloat($splType)) {
if ($value =~ m/^\s*$fp\s*$/) {
$value = $1;
} else {
return undef;
}
} elsif(SPL::CodeGen::Type::isDecimal($splType)) {
if ($value =~ m/^\s*"$fp"\s*$/) {
$value = $1;
} else {
return undef;
}
} elsif(SPL::CodeGen::Type::isRString($splType) or
# already caught many invalid cases above
return undef if $value =~ m/^lit\$/;
# Handle embedded NULs
$value =~ s/^SPL::rstring\((.*)\)$/$1/;
if ($value =~ m/^(.*), \d+$/) {
# There are NULs in the string
$value = $1;
$value =~ s/\\0" "/\\0"."/g;
}
# Handle embedded @ and $
$value =~ s/\@/\\\@/g;
$value =~ s/\$/\\\$/g;
$value = eval($value);
} elsif(SPL::CodeGen::Type::isBoolean($splType)) {
# already caught invalid cases above
$value = ($value eq 'true') ? 1 : 0;
} else {
return undef;
}
return $value;
}

◆ emitSubmitOutputTuple()

Generate code to submit a tuple to a given output port. If the output
attribute assignments indicate that the tuple is simply forwarded from the
given input port, then the generated code will not create a separate tuple
and will just forward the input one, as long as the port mutability settings
allow it.

Parameters
open/close icon Code:
click to view
# Number of lines of code in emitSubmitOutputTuple: 22
{
my ($outputPort, $inputPort) = @_;
my $index = $outputPort->getIndex();
if (isInputTupleForwarded ($outputPort, $inputPort, 0)) {
# There is one potential problem: the output tuple is mutating, and the input
# one isn't. Generate a copy ctr instead in this case
my $cppName = $inputPort->getCppTupleName();
if ($outputPort->getMutationAllowed() && !$inputPort->getMutationAllowed()) {
# we have to make a copy, or this will fail to compile
emitALine "OPort${index}Type otuple($cppName); submit (otuple, $index);";
} else {
# we are directly submitting the input tuple
emitALine "submit ($cppName, $index);";
}
} else {
# we have to do this the hard way
my $assignments = SPL::CodeGen::getOutputTupleCppInitializer($outputPort);
emitALine "OPort${index}Type otuple($assignments); submit (otuple, $index);";
}
}

◆ emitSubmitCachedOutputTuple()

Generate code to submit a cached tuple to a given output port. If the output
attribute assignments indicate that the tuple is simply forwarded from the
given input port, then the generated code will not populate the cached tuple
and will just forward the input one, as long as the port mutability settings
allow it.

Parameters
open/close icon Code:
click to view
# Number of lines of code in emitSubmitCachedOutputTuple: 22
{
my ($cachedTupleName, $outputPort, $inputPort) = @_;
my $index = $outputPort->getIndex();
if (isInputTupleForwarded ($outputPort, $inputPort, 0)) {
# There is one potential problem: the output tuple is mutating, and the input
# one isn't. Generate a copy ctr instead in this case
my $cppName = $inputPort->getCppTupleName();
if ($outputPort->getMutationAllowed() && !$inputPort->getMutationAllowed()) {
# we have to make a copy, or this will fail to compile
emitALine "$cachedTupleName = $cppName; submit ($cachedTupleName, $index);";
} else {
# we are directly submitting the input tuple
emitALine "submit ($cppName, $index);";
}
} else {
# we have to do this the hard way
my $assignments = SPL::CodeGen::getOutputTupleCppAssignments($cachedTupleName, $outputPort);
emitALine "$assignments submit ($cachedTupleName, $index);";
}
}

◆ emitClass()

Given a name and a list of types, generates a C++ class that is hashable and
contains member fields with the specified types. The class will have public
members with the names 'field<index>_', one for each element in the $types
list. The class will also have empty, copy, and member initializer
constructors, assignment operator, as well as equality and non-equality
comparison operators.

Parameters
Returns
the name of the class, which is different than the parameter
name.
NOTE: emitClass() call should come before the headerPrologue() call.

Example usage from within a code generator template:
<br> // This is an <opname>_h.cgt file
<br> <%
<br> my $keyParam = $model->getParameterByName("key");
<br> my @keyTypes = SPL::CodeGen::getParameterCppTypes($keyParam);
<br> my $keyClass = SPL::CodeGen::emitClass($model, "MyKey", @keyTypes);
<br> ...
<br> %>
<br>

open/close icon Code:
click to view
# Number of lines of code in emitClass: 168
sub emitClass($$@)
{
my ($model, $name, @types) = @_;
return if(scalar(@types)==0);
my $context = $model->getContext();
my $class = $context->getClass();
$name = "${class}\$${name}";
$name =~ s/::/\$/g;
emitALine "#ifndef ${name}_H";
emitALine "#define ${name}_H";
emitALine "#include <SPL/Runtime/Type/SPLType.h>";
emitALine "#include <SPL/Runtime/Serialization/ByteBuffer.h>";
emitALine "#include <SPL/Runtime/Utility/TimeUtils.h>";
SPL::CodeGenHelper::operatorIncludes($context);
emitALine "";
emitALine "class ${name} {";
emitALine "public:";
# empty and copy constructor
emitALine " ${name}() {}\n\n";
emitALine " ${name}(const ${name} & o) :";
foreach(my $i=0; $i<scalar(@types); ++$i) {
my $type = $types[$i];
my $line = "field${i}_(o.field${i}_)";
$line .= "," if($i!=scalar(@types)-1);
emitALine " ${line}";
}
emitALine " {}";
emitALine "";
# constructor
emitALine " ${name}(";
foreach(my $i=0; $i<scalar(@types); ++$i) {
my $type = $types[$i];
my $line = "const ${type} & field${i}";
$line .= "," if($i!=scalar(@types)-1);
emitALine " ${line}";
}
emitALine " ) :";
foreach(my $i=0; $i<scalar(@types); ++$i) {
my $line = "field${i}_(field${i})";
$line .= "," if($i!=scalar(@types)-1);
emitALine " ${line}";
}
emitALine " {}";
emitALine "";
# getters
foreach(my $i=0; $i<scalar(@types); ++$i) {
my $type = $types[$i];
emitALine " ${type} & get_field${i}() {";
emitALine " return field${i}_;";
emitALine " }";
emitALine "";
emitALine " ${type} const & get_field${i}() const {";
emitALine " return field${i}_;";
emitALine " }";
emitALine "";
}
# assignment
emitALine " const ${name} & operator=(${name} const & o) {";
emitALine " if(this==&o) return *this;";
foreach(my $i=0; $i<scalar(@types); ++$i) {
emitALine " field${i}_ = o.field${i}_;";
}
emitALine " return *this;";
emitALine " }";
emitALine "";
# equality
emitALine " bool operator==(${name} const & o) const {";
foreach(my $i=0; $i<scalar(@types); ++$i) {
emitALine " if(field${i}_ != o.field${i}_) return false;";
}
emitALine " return true;";
emitALine " }";
emitALine "";
# inequality
emitALine " bool operator!=(${name} const & o) const {";
emitALine " return !(*this==o);";
emitALine " }";
emitALine "";
# hash function
emitALine " size_t hashCode() const {";
emitALine " size_t r = 17;";
emitALine " size_t c;";
foreach(my $i=0; $i<scalar(@types); ++$i) {
my $type = $types[$i];
emitALine " c = std::hash<${type} >()(field${i}_);";
emitALine " r = 37 * r + c;";
}
emitALine " return r;";
emitALine " }";
emitALine "";
# Checkpoint
emitALine " template <class S>";
emitALine " void serialize(SPL::ByteBuffer<S> & buf) const {";
foreach(my $i=0; $i<scalar(@types); ++$i) {
my $type = $types[$i];
emitALine " buf << field${i}_;";
}
emitALine " }";
emitALine "";
# Reset
emitALine " template <class S>";
emitALine " void deserialize(SPL::ByteBuffer<S> & buf) {";
foreach(my $i=0; $i<scalar(@types); ++$i) {
my $type = $types[$i];
emitALine " buf >> field${i}_;";
}
emitALine " }";
emitALine "";
# variables
foreach(my $i=0; $i<scalar(@types); ++$i) {
my $type = $types[$i];
emitALine " ${type} field${i}_;";
}
emitALine "};";
# overload operator<<() for checkpointing
emitALine "template <class S>";
emitALine "inline SPL::ByteBuffer<S> & operator<<(SPL::ByteBuffer<S> & buf, const ${name} & v)";
emitALine "{";
emitALine " v.serialize(buf); return buf;";
emitALine "}";
# overload operator>>() for restoring
emitALine "template <class S>";
emitALine "inline SPL::ByteBuffer<S> & operator>>(SPL::ByteBuffer<S> & buf, ${name} & v)";
emitALine "{";
emitALine " v.deserialize(buf); return buf;";
emitALine "}";
emitALine "";
# functional hash
emitALine "namespace std {";
emitALine " template <>";
emitALine " struct hash<${name} > {";
emitALine " size_t operator()(${name} const & val) const {";
emitALine " return val.hashCode();";
emitALine " }";
emitALine " };";
emitALine "}";
emitALine "";
# FormattedOutputFunction and checkpoint streaming operators
emitALine "namespace SPL {";
emitALine " std::ostream & operator<<(std::ostream & ostr, ${name} const & x) {";
foreach(my $i=0; $i<scalar(@types); ++$i) {
emitALine " ostr << x.get_field${i}();";
}
emitALine " return ostr;";
emitALine " }";
emitALine "";
emitALine "}";
emitALine "";
emitALine "#endif /* ${name}_H */";
emitALine "";
return $name;
}

◆ getWindowCppType()

Given a window object from the operator instance model, returns the C++ type
for the window.

Parameters
open/close icon Code:
click to view
# Number of lines of code in getWindowCppType: 28
sub getWindowCppType($$;$$$$)
{
my ($window, $tupleType, $partitionType, $dataType, $storageType) = @_;
my $windowCppType =
($window->isTimeInterval()) ?
'SPL::TimeIntervalWindow' :
($window->isTumbling()) ?
'SPL::TumblingWindow' :
'SPL::SlidingWindow';
if(!defined($partitionType)) {
return "$windowCppType<$tupleType >";
}
my $partitionCppType = ($partitionType eq '') ? 'int32_t' : $partitionType;
if(!defined($dataType)) {
return "$windowCppType<$tupleType, $partitionCppType >";
}
my $dataCppType = "std::deque<$tupleType >";
if($dataType eq 'SPL::IncrDeque') {
$dataCppType = "SPL::IncrDeque<$tupleType >";
}
my $storageCppType = "std::unordered_map<$partitionCppType, $dataCppType >";
if(defined($storageType) and ($storageType eq 'SPL::IncrUnorderedMap')) {
$storageCppType = "SPL::IncrUnorderedMap<$partitionCppType, $dataCppType >";
}
return "$windowCppType<$tupleType, $partitionCppType, $dataCppType, $storageCppType >";
}

◆ getWindowCppInitializer()

Given a window object from the operator instance model, returns the C++ type
initializer for the window.

Parameters
Note
This routine will NOT handle partition eviction policies

Example: For a sliding window with a count-based eviction policy of size 10
and a delta-based trigger policy on an int32 attribute with a delta of 15, the call
- getWindowCppInitializer($window, "MyTupleT", "", "get_age")

will produce the following:
- *this, 0, SPL::CountWindowPolicy(10), SPL::DeltaWindowPolicy<MyTupleT,uint32,&MyTupleT::get_age>(15)
open/close icon Code:
click to view
# Number of lines of code in getWindowCppInitializer: 15
{
my ($window, $tupleType, $attrbGetterE, $attrbGetterT) = @_;
my $port = $window->getPortIndex();
my $epolInit = getWindowPolicyCppObject($window, 1, $tupleType, $attrbGetterE);
# warn the user that we are not using the partition eviction policy
SPL::CodeGenHelper::warnPartitionEvictionPolicyIgnored ($window)
if ($window->hasPartitionEvictionPolicy());
if($window->isTumbling() || $window->isTimeInterval()) {
return "*this, ${port}, ${epolInit}";
} else { # sliding
my $tpolInit = getWindowPolicyCppObject($window, 0, $tupleType, $attrbGetterT);
return "*this, ${port}, ${epolInit}, ${tpolInit}";
}
}

◆ getPartitionedWindowCppInitializer()

Given a window object for a partitioned window from the operator instance model,
returns the C++ type initializer for the window.

Parameters
open/close icon Code:
click to view
# Number of lines of code in getPartitionedWindowCppInitializer: 17
{
my ($window, $tupleType, $selectionType, $attrbGetterE, $attrbGetterT) = @_;
my $port = $window->getPortIndex();
my $epolInit = getWindowPolicyCppObject($window, 1, $tupleType, $attrbGetterE);
my $partitionEvictionPolicy =
SPL::CodeGen::errorln (SPL::Msg::INVALID_PARTITION_EVICTION_SELECTOR($selectionType))
unless $selectionType eq 'LRU' || $selectionType eq 'OperatorDefined';
if($window->isTumbling() || $window->isTimeInterval()) {
# no partition eviction policy for event time window
return "*this, ${port}, ${epolInit}${partitionEvictionPolicy}";
} else { # sliding
my $tpolInit = getWindowPolicyCppObject($window, 0, $tupleType, $attrbGetterT);
return "*this, ${port}, ${epolInit}, ${tpolInit}${partitionEvictionPolicy}";
}
}

◆ getWindowPolicyCppObject()

Given a window object from the operator instance model and a window policy,
returns the code that creates a C++ object for the policy

Parameters
open/close icon Code:
click to view
# Number of lines of code in getWindowPolicyCppObject: 73
{
my ($window, $eviction, $tupleType, $attrbGetter) = @_;
my ($policyType, $deltaType, $deltaAttrbGetter, $size);
if ($window->isTimeInterval()) {
my ($intervalDuration, $creationPeriod, $discardAge, $intervalOffset, $resolution);
$intervalDuration = $window->getIntervalDuration()->getCppExpression();
if ($window->hasCreationPeriod()) {
$creationPeriod = $window->getCreationPeriod()->getCppExpression();
}
else {
$creationPeriod = $intervalDuration;
}
if ($window->hasDiscardAge()) {
$discardAge = $window->getDiscardAge()->getCppExpression();
}
else {
$discardAge = "0.0";
}
if ($window->hasIntervalOffset()) {
$intervalOffset = $window->getIntervalOffset()->getCppExpression();
}
else {
$intervalOffset = "0.0";
}
my $policy = "::SPL::TimeIntervalWindowOptions().setIntervalDuration(timestamp($intervalDuration)).setCreationPeriod(timestamp($creationPeriod)).setDiscardAge(timestamp($discardAge)).setIntervalOffset(timestamp($intervalOffset))";
return $policy;
}
if ($eviction) {
$policyType = $window->getEvictionPolicyType();
$size = $window->getEvictionPolicySize()->getCppExpression()
if ($policyType!=$SPL::Operator::Instance::Window::PUNCT);
if ($policyType==$SPL::Operator::Instance::Window::DELTA) {
$deltaType = $window->getEvictionPolicyAttribute()->getCppType();
$deltaAttrbGetter = $window->getEvictionPolicyAttribute()->getCppExpression()
if(not $attrbGetter);
}
} else {
$policyType = $window->getTriggerPolicyType();
$size = $window->getTriggerPolicySize()->getCppExpression()
if ($policyType!=$SPL::Operator::Instance::Window::PUNCT);
if ($policyType==$SPL::Operator::Instance::Window::DELTA) {
$deltaType = $window->getTriggerPolicyAttribute()->getCppType();
$deltaAttrbGetter = $window->getTriggerPolicyAttribute()->getCppExpression()
if(not $attrbGetter);
}
}
if((not $attrbGetter) and $deltaAttrbGetter) {
$attrbGetter = $deltaAttrbGetter;
$attrbGetter =~ s/^[^\.]*\.//; # iport0.get_age() -> get_age()
$attrbGetter =~ s/\s*\(\s*\)\s*$//; # get_age() -> get_age
}
my $ret = "";
if ($policyType==$SPL::Operator::Instance::Window::COUNT) {
$ret = "::SPL::CountWindowPolicy(${size})";
} elsif ($policyType==$SPL::Operator::Instance::Window::DELTA) {
my $baseTupleType = $tupleType;
$baseTupleType =~ s/\*\s*$//; # T * -> T
$baseTupleType =~ s/^const //; # const T -> T
$ret = "::SPL::DeltaWindowPolicy<${tupleType},${deltaType},&" .
"${baseTupleType}::${attrbGetter}>(${size})";
} elsif ($policyType==$SPL::Operator::Instance::Window::TIME) {
$ret = "::SPL::TimeWindowPolicy(${size})";
} elsif ($policyType==$SPL::Operator::Instance::Window::PUNCT) {
$ret = "::SPL::PunctWindowPolicy()";
}
return $ret;
}

◆ getWindowPartitionEvictionPolicyInitializer()

Given a window object from the operator instance model, returns the C++ initializer
that can be appended to the window initializer to set the partition evicition policy.
If there is no partition eviction policy, return an empty string

Parameters
open/close icon Code:
click to view
# Number of lines of code in getWindowPartitionEvictionPolicyInitializer: 23
{
my ($window, $selectionType) = @_;
return "" if (!$window->hasPartitionEvictionPolicy());
my ($kind, $value);
my $pKind = $window->getPartitionEvictionPolicyKind();
my $selector;
if ($pKind eq "partitionAge") {
$kind = "PartitionAge";
$value = $window->getPartitionEvictionPolicyAge();
} elsif ($pKind eq "partitionCount") {
$kind = "PartitionCount";
$value = $window->getPartitionEvictionPolicyCount();
$selector = $selectionType;
} else {
$kind = "TupleCount";
$value = $window->getPartitionEvictionPolicyCount();
$selector = $selectionType;
}
$selector = $selector ? ", ::SPL::PartitionEvictionPolicy::$selector" : "";
$value = $value->getCppExpression();
return ", ::SPL::${kind}PartitionEvictionPolicy($value$selector)";
}

◆ getWindowEventCppType()

Given a window object from the operator instance model, returns the C++ type
for the WindowEvent class that is used to handle events from the window.

Parameters
open/close icon Code:
click to view
# Number of lines of code in getWindowEventCppType: 20
sub getWindowEventCppType($$;$$$$)
{
my ($window, $tupleType, $partitionType, $dataType, $storageType) = @_;
if(!defined($partitionType)) {
return "SPL::WindowEvent<$tupleType >";
}
my $partitionCppType = ($partitionType eq '') ? 'int32_t' : $partitionType;
if(!defined($dataType)) {
return "SPL::WindowEvent<$tupleType, $partitionCppType >";
}
my $dataCppType = "std::deque<$tupleType >";
if($dataType eq 'SPL::IncrDeque') {
$dataCppType = "SPL::IncrDeque<$tupleType >";
}
my $storageCppType = "std::unordered_map<$partitionCppType, $dataCppType >";
if(defined($storageType) and ($storageType eq 'SPL::IncrUnorderedMap')) {
$storageCppType = "SPL::IncrUnorderedMap<$partitionCppType, $dataCppType >";
}
return "SPL::WindowEvent<$tupleType, $partitionCppType, $dataCppType, $storageCppType >";
}

◆ createWindowConfigurations()

Given a list of window configurations, verify that the configurations are
valid and return a reference to a list of configurations that can be used as
input to SPL::CodeGen::validateWindowConfiguration validateWindowConfiguration and br>SPL::CodeGen::checkWindowConfigurationcheckWindowConfiguration@endlink<br>functions.Theinputlistcontainsonehashreferenceforeach<br>configuration.Ahashthatrepresentsawindowconfigurationcontainsoneor<br>moreofthefollowingmappings:<br>-type=>\<window-type\>,wherethewindowtypeisoneof<br>$SPL::Operator::Instance::Window::TUMBLINGandSLIDING.<br>-eviction=>\<eviction-policy\>,wheretheevictionpolicyisoneof<br>$SPL::Operator::Instance::Window::COUNT,DELTA,TIME,andPUNCT.<br>-trigger=>\<trigger-policy\>,wherethetriggerpolicyisoneof<br>$SPL::Operator::Instance::Window::COUNT,DELTA,andTIME.<br>-partitioned=>\<partition-status\>,wherethepartitionstatusis0or1.<br>Thesemappingsaretreatedasconjunctions.<br>@paramconfslistofvalidwindowconfigurations<br>@paramconfsreferencetothelistofvalidwindowconfigurations<br>@returnareferencetothelistofconfigurations<br><br>HereisanexampleusefromtheSortoperator,whichcreatestwo<br>configurations,onethatacceptsanytumblingwindow,anotheronethat<br>acceptsslidingwindowswithcountbasedtriggerandevictionpolicies:<br>@code<br>my$confs=SPL::CodeGen::createWindowConfigurations(<br>type=>$SPL::Operator::Instance::Window::TUMBLING,<br>type=>$SPL::Operator::Instance::Window::SLIDING,<br>eviction=>$SPL::Operator::Instance::Window::COUNT,<br>trigger=>$SPL::Operator::Instance::Window::COUNT);<br>\endcode<br>@htmlonly[block]<divid='codesection-createWindowConfigurations'class='dynheaderclosed'style='cursor:pointer;'onclick='returntoggleVisibility(this)'><imgid='codesection-createWindowConfigurations-trigger'src='closed.png'alt='open/closeicon'style='display:inline'/><b>Code:</b></div><divid='codesection-createWindowConfigurations-summary'class='dyncontent'style='display:block;font-size:small;'>clicktoview</div><divid='codesection-createWindowConfigurations-content'class='dyncontent'style='display:none;'>@endhtmlonly@code#NumberoflinesofcodeincreateWindowConfigurations:40subcreateWindowConfigurationsmy(@confs)=@_;foreachmy$conf(@confs)my$type=$conf->type;my$partitioned=$conf->partitioned;my$eviction=$conf->eviction;my$trigger=$conf->trigger;if(defined($type))SPL::CodeGen::exitln(SPL::Msg::UNKNOWN_WINDOW_PROPERTY_VALUE($type, "type"))if($typene"$SPL::Operator::Instance::Window::TUMBLING"&&$typene"$SPL::Operator::Instance::Window::SLIDING"&&$typene"$SPL::Operator::Instance::Window::TIME_INTERVAL");if(defined($partitioned))SPL::CodeGen::exitln(SPL::Msg::UNKNOWN_WINDOW_PROPERTY_VALUE($partitioned, "partitioned"))if($partitioned ne "0" && $partitioned ne "1");if(defined($eviction))SPL::CodeGen::exitln(SPL::Msg::UNKNOWN_WINDOW_PROPERTY_VALUE($eviction, "eviction"))if($evictionne"$SPL::Operator::Instance::Window::COUNT"&&$evictionne"$SPL::Operator::Instance::Window::DELTA"&&$evictionne"$SPL::Operator::Instance::Window::TIME"&&$evictionne"$SPL::Operator::Instance::Window::PUNCT");if(defined($trigger))SPL::CodeGen::exitln(SPL::Msg::UNKNOWN_WINDOW_PROPERTY_VALUE($trigger, "trigger"))if($triggerne"$SPL::Operator::Instance::Window::COUNT"&&$triggerne"$SPL::Operator::Instance::Window::DELTA"&&$triggerne"$SPL::Operator::Instance::Window::TIME"&&$triggerne"$SPL::Operator::Instance::Window::PUNCT");my%validKeys=("type"=>1,"partitioned"=>1,"eviction"=>1,"trigger"=>1);foreachmy$key(keys%$conf)SPL::CodeGen::exitln(SPL::Msg::UNKNOWN_WINDOW_PROPERTY_KEY($key))if(not $validKeys{$key});return\@confs;@endcode@htmlonly[block]</div>@endhtmlonly

◆ validateWindowConfiguration()

Given an input port and a list of window configurations (created via br>SPL::CodeGen::createWindowConfigurationscreateWindowConfigurations@endlink),<br>verifiesthattheinputporthasavalidwindowconfiguration.Printsan<br>errormessageandexitsifthewindowconfigurationoftheinputportisnot<br>amongtheprovidedconfigurations.<br>@paramiporttheinputportobjectfromtheoperatorinstancemodel<br>@paramconfsalistofvalidwindowconfigurations,see<br>createWindowConfigurationsfunctionfordetails.<br><br>Exampleusefromthe\cSortoperator:<br>@code<br>my$confs=SPL::CodeGen::createWindowConfigurations(<br>type=>$SPL::Operator::Instance::Window::TUMBLING,<br>type=>$SPL::Operator::Instance::Window::SLIDING,<br>eviction=>$SPL::Operator::Instance::Window::COUNT,<br>trigger=>$SPL::Operator::Instance::Window::COUNT);<br>my$iport=$model->getInputPortAt(0);<br>SPL::CodeGen::validateWindowConfiguration($iport, $confs);<br>\endcode<br>@htmlonly[block]<divid='codesection-validateWindowConfiguration'class='dynheaderclosed'style='cursor:pointer;'onclick='returntoggleVisibility(this)'><imgid='codesection-validateWindowConfiguration-trigger'src='closed.png'alt='open/closeicon'style='display:inline'/><b>Code:</b></div><divid='codesection-validateWindowConfiguration-summary'class='dyncontent'style='display:block;font-size:small;'>clicktoview</div><divid='codesection-validateWindowConfiguration-content'class='dyncontent'style='display:none;'>@endhtmlonly@code#NumberoflinesofcodeinvalidateWindowConfiguration:12subvalidateWindowConfiguration($$)my($iport,$confs)=@_;returnif(1==checkWindowConfiguration($iport,$confs));if($iport->hasWindow())SPL::CodeGen::exitln(SPL::Msg::STDTK_UNSUPPORTED_WINDOW_CONFIGURATION($iport->getIndex()),$iport->getWindow()->getSourceLocation());elseSPL::CodeGen::exitln(SPL::Msg::STDTK_UNSUPPORTED_WINDOW_CONFIGURATION($iport->getIndex()),$iport->getSourceLocation());@endcode@htmlonly[block]</div>@endhtmlonly

◆ checkWindowConfiguration()

Given an input port and a list of window configurations (created via br>SPL::CodeGen::createWindowConfigurationscreateWindowConfigurations@endlink),<br>checksiftheinputporthasavalidwindowconfiguration.Returns0ifthe<br>windowconfigurationoftheinputportisnotamongtheprovided<br>configurations,and1otherwise.<br>@paramiporttheinputportobjectfromtheoperatorinstancemodel<br>@paramconfsalistofvalidwindowconfigurations,see<br>createWindowConfigurationsfunctionfordetails.<br>@return1iftheconfigurationisvalid,0otherwise<br><br>Exampleusefromthe\cSortoperator:<br>@code<br>my$confs=SPL::CodeGen::createWindowConfigurations(<br>type=>$SPL::Operator::Instance::Window::TUMBLING,<br>type=>$SPL::Operator::Instance::Window::SLIDING,<br>eviction=>$SPL::Operator::Instance::Window::COUNT,<br>trigger=>$SPL::Operator::Instance::Window::COUNT);<br>my$iport=$model->getInputPortAt(0);<br>my$res=SPL::CodeGen::checkWindowConfiguration($iport, $confs);<br>\endcode<br>@htmlonly[block]<divid='codesection-checkWindowConfiguration'class='dynheaderclosed'style='cursor:pointer;'onclick='returntoggleVisibility(this)'><imgid='codesection-checkWindowConfiguration-trigger'src='closed.png'alt='open/closeicon'style='display:inline'/><b>Code:</b></div><divid='codesection-checkWindowConfiguration-summary'class='dyncontent'style='display:block;font-size:small;'>clicktoview</div><divid='codesection-checkWindowConfiguration-content'class='dyncontent'style='display:none;'>@endhtmlonly@code#NumberoflinesofcodeincheckWindowConfiguration:35subcheckWindowConfiguration($$)my($iport,$confs)=@_;if(not $iport->hasWindow())if(scalar(@{$confs}))return0;elsereturn1;my$match=0;my$window=$iport->getWindow();foreachmy$conf(@$confs)my$type=$conf->type;my$partitioned=$conf->partitioned;my$eviction=$conf->eviction;my$trigger=$conf->trigger;if(defined($type))nextif($type!=$window->getWindowType());if(defined($partitioned))nextif($partitioned!=$window->isPartitioned());if(defined($eviction))nextif($eviction!=$window->getEvictionPolicyType());if(defined($trigger))nextif($trigger!=$window->getTriggerPolicyType());$match=1;last;return$match;@endcode@htmlonly[block]</div>@endhtmlonly

◆ isInputTupleForwarded()

Check if the output tuple to be created is an exact copy of the input tuple

Parameters
Returns
1 if the input tuple is used directly to generate the output tuple
open/close icon Code:
click to view
# Number of lines of code in isInputTupleForwarded: 29
{
my ($outputPort, $inputPort, $checkMutation) = @_;
# easy case: different types
return 0 if $inputPort->getCppTupleType() ne $outputPort->getCppTupleType();
# another one to check. Are the mutation settings okay? In other words,
# we can't pass a non-mutating input to a mutating output
return 0 if $checkMutation &&
$outputPort->getMutationAllowed() && !$inputPort->getMutationAllowed();
# check all the assignment expressions to see if they match
my $numAttrs = $outputPort->getNumberOfAttributes();
my $iportName = $inputPort->getCppTupleName();
for (my $i = 0; $i < $numAttrs; ++$i) {
my $attr = $outputPort->getAttributeAt($i);
my $name = $attr->getName();
my $exp = $attr->getAssignmentValue();
# is there a matching output expression?
return 0 if !$exp;
my $cppExpn = $exp->getCppExpression();
# look for iport$N.get_ATTRIBUTE()
return 0 if $cppExpn ne ($iportName . ".get_" . $name . "()");
}
# all matched
return 1;
}

◆ checkMinimalSchema()

Given an input or output port, and a list of schema restrictions, ensure that the tuple that
the port is consuming/producing contains all of the desired schema name/types.
If there are attributes/types missing from the tuple, generate an error.
For each restriction, there must be at least one attribute that satisfies it.

Parameters
open/close icon Code:
click to view
# Number of lines of code in checkMinimalSchema: 37
{
my ($port, @schema) = @_;
foreach my $s (@schema) {
my $name = $s->{name};
my $type = $s->{type};
if (defined($name)) {
my $a = $port->getAttributeByName($name);
if (!defined ($a)) {
SPL::CodeGen::errorln (SPL::Msg::NAME_NOT_FOUND_IN_SCHEMA($port->getIndex(), $name),
$port->getSourceLocation());
} elsif (defined ($type)) {
# does $a have the right type?
my $possibleTypes;
if (!SPL::CodeGenHelper::checkTypeMatches ($a->getSPLType(), $type, \$possibleTypes)) {
SPL::CodeGen::errorln (SPL::Msg::NAME_WRONG_TYPE_IN_SCHEMA($port->getIndex(),
$name, $a->getSPLType(), $possibleTypes), $port->getSourceLocation());
}
}
} elsif (defined($type)) {
# look for any attribute with given type
my $seen = 0;
for (my $i = 0; $i < $port->getNumberOfAttributes(); $i++) {
my $possibleTypes;
if (SPL::CodeGenHelper::checkTypeMatches ($port->getAttributeAt($i)->getSPLType(), $type, \$possibleTypes)) {
$seen = 1;
last;
}
}
if (!$seen) {
SPL::CodeGen::errorln (SPL::Msg::TYPE_NOT_FOUND_IN_SCHEMA($port->getIndex(),
join ('/', $type)), $port->getSourceLocation());
}
}
}
CORE::exit $SPL::CodeGen::USER_ERROR if ($SPL::CodeGen::sawError);
}

◆ checkMaximalSchema()

Given an input or output port, and a list of schema restrictions, ensure that the tuple that
the port is consuming/producing only contains attributes with the desired schema name/types.
If there are attributes or types in the schema that are not supported, generate an error.
For each attribute, there must be at least one restriction that permits it.

Parameters
open/close icon Code:
click to view
# Number of lines of code in checkMaximalSchema: 43
{
my ($port, @schema) = @_;
# walk the attributes;
for (my $i = 0; $i < $port->getNumberOfAttributes(); $i++) {
my $a = $port->getAttributeAt($i);
my $aName = $a->getName();
my $aType = $a->getSPLType();
# is there a match for this name?
my $seen = 0;
my $possibleTypes;
foreach my $s (@schema) {
my $name = $s->{name};
my $type = $s->{type};
if (defined ($name) && $aName eq $name) {
# This is a name match. Does the type (if present) match too?
if (!defined ($type) || SPL::CodeGenHelper::checkTypeMatches($aType, $type, \$possibleTypes)) {
$seen = 1;
last;
}
} elsif (defined($type)) {
my $possibleTypes;
if (SPL::CodeGenHelper::checkTypeMatches($aType, $type, \$possibleTypes)) {
# type match
$seen = 1;
last;
}
}
}
# saw an attribute that didn't match; complain
if (!$seen) {
if (defined ($possibleTypes)) {
SPL::CodeGen::errorln (SPL::Msg::ATTRIBUTE_NOT_ALLOWED_IN_SCHEMA_VALID_TYPES($port->getIndex(), $aName, $aType, $possibleTypes),
$port->getSourceLocation());
} else {
SPL::CodeGen::errorln (SPL::Msg::ATTRIBUTE_NOT_ALLOWED_IN_SCHEMA($port->getIndex(), $aName, $aType),
$port->getSourceLocation());
}
}
}
CORE::exit $SPL::CodeGen::USER_ERROR if ($SPL::CodeGen::sawError);
}

◆ checkAnySchema()

Given an input or output port, and a list of schema restrictions, ensure that the tuple that
the port is consuming/producing contains attributes of the right names/types.
If an attribute in the tuple is in the list of restrictions, it must have the right type.
Any attributes NOT in the schema restrictions are accepted without errors.
For each attribute, there must be at least one restriction with a matching name that is satisfied.

Parameters
open/close icon Code:
click to view
# Number of lines of code in checkAnySchema: 25
sub checkAnySchema($@)
{
my ($port, @schema) = @_;
foreach my $s (@schema) {
my $name = $s->{name};
my $type = $s->{type};
# ignore records that don't have both name and type
next if !defined($type) || !defined($name);
my $a = $port->getAttributeByName($name);
# if we don't have a name in the tuple schema that matches, we are fine
next if !defined ($a);
# does $a have the right type?
my $possibleTypes;
if (!SPL::CodeGenHelper::checkTypeMatches ($a->getSPLType(), $type, \$possibleTypes)) {
SPL::CodeGen::errorln (SPL::Msg::NAME_WRONG_TYPE_IN_SCHEMA($port->getIndex(), $name,
$a->getSPLType(), $possibleTypes),
$port->getSourceLocation());
}
}
CORE::exit $SPL::CodeGen::USER_ERROR if ($SPL::CodeGen::sawError);
}

◆ print()

This function allows printing to the console during code generation. During
code generation STDOUT is redirected. Attempts to print to it will result in
corruption of the code generator. Note that if no optional params are passed
the Perl print function will be called.

Parameters
open/close icon Code:
click to view
# Number of lines of code in print: 9
sub print
{
my ($msg, @params) = @_;
if (scalar(@params) > 0) {
printf $OLDSTDOUT $msg, @params;
} else {
print $OLDSTDOUT $msg;
}
}

◆ println()

This function is similar to the print() method with the addition of a new
line added at the end.

Parameters
open/close icon Code:
click to view
# Number of lines of code in println: 5
sub println
{
print $OLDSTDOUT "\n";
}

◆ printVerbose()

This function is similar to the print() method except that it only prints if the -v or
–verbose-mode compiler option has been specified.

Parameters
open/close icon Code:
click to view
# Number of lines of code in printVerbose: 6
{
if ($verboseMode) {
}
}

◆ printlnVerbose()

This function is similar to the println() method except that it only prints if the -v or
–verbose-mode compiler option has been specified.

Parameters
open/close icon Code:
click to view
# Number of lines of code in printlnVerbose: 6
{
if ($verboseMode) {
}
}

◆ warn()

Prints 'WARNING' plus the contents of the format string.

Parameters
open/close icon Code:
click to view
# Number of lines of code in warn: 20
sub warn
{
my $loc = SPL::CodeGenHelper::location(\@_);
my ($msg, @params) = @_;
my $msgId = "";
my $sev = "";
if ($msg =~ /^(CDISP[0-9][0-9][0-9][0-9][EW] )(.*)/s) {
$msgId = $1;
$msg = $2;
$sev = SPL::Msg::WARNING();
} else {
$sev = SPL::Msg::WARNING_WITH_MESSAGE_ID();
}
print STDERR "${loc}${msgId}${sev}: ";
if (scalar(@params) > 0) {
printf STDERR $msg, @params;
} else {
print STDERR $msg;
}
}

◆ warnln()

This function is the same as warn() with the addition of a newline at the end.

Parameters
open/close icon Code:
click to view
# Number of lines of code in warnln: 5
sub warnln
{
print STDERR "\n";
}

◆ warnVerbose()

This function is the same as warn() except that it only prints if the -v
or –verbose-mode compiler option has been specified.

Parameters
open/close icon Code:
click to view
# Number of lines of code in warnVerbose: 6
{
if ($verboseMode) {
}
}

◆ warnlnVerbose()

This function is the same as warnVerbose() with the addition of a new line at the end.

Parameters
open/close icon Code:
click to view
# Number of lines of code in warnlnVerbose: 7
{
if ($verboseMode) {
print STDERR "\n";
}
}

◆ error()

Prints 'ERROR ' plus the format string to STDERR.

Parameters
open/close icon Code:
click to view
# Number of lines of code in error: 21
sub error
{
my $loc = SPL::CodeGenHelper::location(\@_);
my ($msg, @params) = @_;
my $msgId = "";
my $sev = "";
if ($msg =~ /^(CDISP[0-9][0-9][0-9][0-9]E )(.*)/s) {
$msgId = $1;
$msg = $2;
$sev = SPL::Msg::ERROR();
} else {
$sev = SPL::Msg::ERROR_WITH_MESSAGE_ID();
}
print STDERR "${loc}${msgId}${sev}: ";
if (scalar(@params) > 0) {
printf STDERR $msg, @params;
} else {
print STDERR $msg;
}
$SPL::CodeGen::sawError = 1;
}

◆ errorln()

This function is the same as error() with the addition of a newline at the end.

Parameters
open/close icon Code:
click to view
# Number of lines of code in errorln: 5
sub errorln
{
print STDERR "\n";
}

◆ exit()

This function enables the printing of the format string to STDERR prior to
exiting.

Parameters
open/close icon Code:
click to view
# Number of lines of code in exit: 5
sub exit
{
error(@_);
exit $USER_ERROR;
}

◆ exitln()

This method provides the same functionality as exit with the addition of a
new line at the end.

Parameters
open/close icon Code:
click to view
# Number of lines of code in exitln: 5
sub exitln
{
errorln(@_);
CORE::exit $USER_ERROR;
}

◆ runtimePath()

This method takes a compile-time path and converts it to a runtime path. If the compile-time path
points into a toolkit, then that path will reflect the runtime location of that toolkit, otherwise
the original path will be used.

Parameters
open/close icon Code:
click to view
# Number of lines of code in runtimePath: 5
sub runtimePath($$$)
{
my ($model, $path, $varName) = @_;
SPL::CodeGenHelper::runtimePathImpl($model, $path, $varName);
}

◆ compileTimeExpression()

This method takes a paramenter value representing a run-time path and converts it to an expression that
can be used at compile time to access resources. undef is returned if the parameter value cannot be evaluated.
The operator model must specify <splExpressionTree param="true"> for this to be used.

Parameters
open/close icon Code:
click to view
# Number of lines of code in compileTimeExpression: 10
{
my ($model, $paramValue) = @_;
if (!$paramValue->hasSPLExpressionTree()) {
SPL::CodeGen::errorln(SPL::Msg::MISSING_SPL_EXPRESSION_TREE);
return undef;
}
my $expr = $paramValue->getSPLExpressionTree();
return SPL::CodeGenHelper::evaluateExpression($model, $expr);
}

◆ validateTimeIntervalAttribute()

Undocumented Method

open/close icon Code:
click to view
# Number of lines of code in validateTimeIntervalAttribute: 79
my ($model, $inputPort) = @_;
# If this input port has a timeInterval window, then it must also
# have an event-time attribute, and the attribute must be one
# of the attributes in the tuple
my $isTimeInterval = 0;
my $window;
if ($inputPort->hasWindow()) {
$window = $inputPort->getWindow();
$isTimeInterval = $window->isTimeInterval();
}
if ($isTimeInterval) {
my $eventTimeContext = $model->getContext()->getOptionalContext("EventTime");
my $eventTimeAttribute;
if (defined($eventTimeContext)) {
$eventTimeAttribute = $eventTimeContext->getAttribute();
}
if (!$eventTimeAttribute) {
SPL::CodeGen::errorln(SPL::Msg::MISSING_EVENTTIME_ANNOTATION, $window->getSourceLocation());
}
else {
# find the attribute in any nested types, including the path to it.
my $eventTimeAttributeFound = 1;
my $tupleType = $inputPort->getSPLTupleType;
my @attributeParts = split(/\./, $eventTimeAttribute);
# $primitiveAttribute will be the innermost, primitive attribute
# name. The remaining elements of @attributeParts will be
# any containing tuples.
my $primitiveAttribute = pop @attributeParts;
while ($eventTimeAttributeFound && @attributeParts) {
my $attributePart = shift @attributeParts;
my @attributeNames = SPL::CodeGen::Type::getAttributeNames($tupleType);
my @attributeTypes = SPL::CodeGen::Type::getAttributeTypes($tupleType);
my $attributeCount = @attributeNames;
for (my $attributeIndex = 0; $attributeIndex < $attributeCount; ++$attributeIndex) {
my $attributeName = $attributeNames[$attributeIndex];
my $attributeType = $attributeTypes[$attributeIndex];
if ($attributeName eq $attributePart) {
# if it is a tuple, continue,
if (SPL::CodeGen::Type::isTuple($attributeType)) {
$tupleType = $attributeType;
last;
}
# otherwise, bail
else {
$eventTimeAttributeFound = 0;
last;
}
}
}
}
if ($eventTimeAttributeFound) {
$eventTimeAttributeFound = 0;
my @attributeNames = SPL::CodeGen::Type::getAttributeNames($tupleType);
my @attributeTypes = SPL::CodeGen::Type::getAttributeTypes($tupleType);
my $attributeCount = @attributeNames;
for (my $attributeIndex = 0; $attributeIndex < $attributeCount; ++$attributeIndex) {
my $attributeName = $attributeNames[$attributeIndex];
my $attributeType = $attributeTypes[$attributeIndex];
if ($attributeName eq $primitiveAttribute) {
$eventTimeAttributeFound = 1;
last;
}
}
}
if (!$eventTimeAttributeFound) {
SPL::CodeGen::errorln (SPL::Msg::MISMATCH_ATTRIBUTE_EVENTTIME_ANNOTATION,
$window->getSourceLocation());
}
}
}
}

◆ emitInputPortGetEventTime()

Undocumented Method

open/close icon Code:
click to view
# Number of lines of code in emitInputPortGetEventTime: 24
{
my ($model, $port, $handledAttributeTuplePairs) = @_;
my $eventTimeContext = $model->getContext()->getOptionalContext("EventTime");
if (defined($eventTimeContext)) {
my $inputConnections = $eventTimeContext->getInputConnections();
# @$inputConnections is now a list of triples:
# x,y,z , where x is the port index, y is the connected
# operator index, and z is the connected port index. We
# only need the port index here.
my $portIndex = $port->getIndex();
foreach my $inputConnection (@$inputConnections) {
my ($inputPort, $connectedOperator, $connectedPort) = $inputConnection =~ /([0-9]+),([0-9]+),([0-9]+)/s;
if ($inputPort == $portIndex) {
emitGetEventTime($model, $port, $handledAttributeTuplePairs);
last;
}
}
}
}

◆ emitOutputPortGetEventTime()

Undocumented Method

open/close icon Code:
click to view
# Number of lines of code in emitOutputPortGetEventTime: 15
{
my ($model, $port, $handledAttributeTuplePairs) = @_;
my $eventTimeContext = $model->getContext()->getOptionalContext("EventTime");
if (defined($eventTimeContext)) {
my $outputPorts = $eventTimeContext->getOutputPorts();
my $portIndex = $port->getIndex();
foreach my $outputPort (@$outputPorts) {
if ($outputPort == $portIndex) {
emitGetEventTime($model, $port, $handledAttributeTuplePairs);
last;
}
}
}
}

◆ emitGetEventTime()

Undocumented Method

open/close icon Code:
click to view
# Number of lines of code in emitGetEventTime: 30
sub emitGetEventTime($$$)
{
my ($model, $port, $handledAttributeTuplePairs) = @_;
my $context = $model->getContext();
my $eventTimeContext = $context->getOptionalContext("EventTime");
if (defined($eventTimeContext)) {
my $eventTimeAttribute = $eventTimeContext->getAttribute();
my $eventTimeType = $eventTimeContext->getType();
my $eventTimeResolution = $eventTimeContext->getResolution();
my $tupleType = $port->getCppTupleType();
# check if this attribute/tuple pair has already been handled.
my $matchFound = 0;
my $count = scalar @${handledAttributeTuplePairs};
for (my $index = 0; $index < $count; $index += 2) {
if (($handledAttributeTuplePairs->[$index] eq $eventTimeAttribute)
&& ($handledAttributeTuplePairs->[$index + 1] eq $tupleType)) {
$matchFound = 1;
last;
}
}
if (!$matchFound) {
push (@{$handledAttributeTuplePairs}, $eventTimeAttribute, $tupleType);
emitEventTimeClass($port->getCppTupleType(), $eventTimeAttribute, $eventTimeType, $eventTimeResolution, 1);
}
}
}

◆ emitAllGetEventTime()

Undocumented Method

open/close icon Code:
click to view
# Number of lines of code in emitAllGetEventTime: 26
{
my ($model) = @_;
# Iterate through the input ports and output ports, and find each one with
# an event-time context. For each, emit a getEventTime method.
# Track the attribute names and tuple types, and do not emit
# duplicate definitions.
my @handledAttributeTuplePairs = ();
my $inputPortCount = $model->getNumberOfInputPorts;
for (my $inputPortIndex = 0; $inputPortIndex < $inputPortCount; ++$inputPortIndex) {
my $inputPort = $model->getInputPortAt($inputPortIndex);
# perhaps there is a better place for this validation
validateTimeIntervalAttribute($model, $inputPort);
emitInputPortGetEventTime($model, $inputPort, \@handledAttributeTuplePairs);
}
my $outputPortCount = $model->getNumberOfOutputPorts;
for (my $outputPortIndex = 0; $outputPortIndex < $outputPortCount; ++$outputPortIndex) {
my $outputPort = $model->getOutputPortAt($outputPortIndex);
emitOutputPortGetEventTime($model, $outputPort, \@handledAttributeTuplePairs);
}
}

◆ emitEventTimeClass()

Undocumented Method

open/close icon Code:
click to view
# Number of lines of code in emitEventTimeClass: 49
sub emitEventTimeClass($$$$$)
{
my ($tupleType, $eventTimeAttribute, $eventTimeType, $eventTimeResolution, $includeSetter) = @_;
$eventTimeType =~ s/SPL:://;
my @path = split /\./, $eventTimeAttribute;
$eventTimeAttribute = pop @path;
my $callPath = "";
if (@path) {
$callPath = "get_" . join("().get_", @path) . "().";
}
emitALine " template <>";
emitALine " struct EventTime<" . $tupleType . " > {";
emitALine " typedef " . $tupleType . " TupleType;";
emitALine " typedef " . $eventTimeType . " EventTimeType; // The type of the event time attribute";
emitALine " static EventTimeType get (TupleType const & t)";
emitALine " { return t." . $callPath . "get_" . $eventTimeAttribute . "(); }";
emitALine " static EventTimeType fromTimestamp(timestamp const & ts)";
if ($eventTimeType eq "timestamp") {
emitALine " { return ts; }";
}
else {
emitALine " { return SPL::Functions::EventTime::" . $eventTimeType . "TicksFromTimestamp(ts, SPL::Functions::EventTime::" . $eventTimeResolution . "); }";
}
emitALine " static timestamp toTimestamp(TupleType const & t)";
emitALine " { return toTimestamp(get(t)); }";
emitALine " static timestamp toTimestamp(EventTimeType t) ";
if ($eventTimeType eq "timestamp") {
emitALine " { return t; }";
}
else {
emitALine " { return SPL::Functions::EventTime::toTimestamp" . "(t, SPL::Functions::EventTime::" . $eventTimeResolution . "); }";
}
# setEventTime is always passed a timestamp. The generated
# code should convert it to the event time type, taking into
# consideration the resolution in use.
if ($includeSetter) {
emitALine " static void setEventTime(TupleType & tuple, timestamp const & ts)";
emitALine " { tuple." . $callPath . "set_" . $eventTimeAttribute . "(fromTimestamp(ts)); }";
}
emitALine " };";
}

◆ hasEventTimeContext()

Undocumented Method

open/close icon Code:
click to view
# Number of lines of code in hasEventTimeContext: 5
my ($model) = @_;
my $eventTimeContext = $model->getContext()->getOptionalContext("EventTime");
defined($eventTimeContext);
}