Operator implementation
You use skeleton template files that are generated by the spl-make-operator script as the basis for operator implementations.
Header file
<%SPL::CodeGen::headerPrologue($model);%>
class MY_OPERATOR : public MY_BASE_OPERATOR {
public:
// constructor
MY_OPERATOR();
// destructor
virtual ~MY_OPERATOR();
// notify port readiness
void allPortsReady();
// notify termination
void prepareToShutdown();
// processing for source and threaded operators
void process(uint32_t idx);
// tuple processing for mutating ports
void process(Tuple & tuple, uint32_t port);
// tuple processing for non-mutating ports
void process(Tuple const & tuple, uint32_t port);
// punctuation processing
void process(Punctuation const & punct, uint32_t port);
};
<%SPL::CodeGen::headerEpilogue($model);%>
Implementation file
<%SPL::CodeGen::implementationPrologue($model);%>
MY_OPERATOR::MY_OPERATOR()
: MY_BASE_OPERATOR() {}
MY_OPERATOR::~MY_OPERATOR() {}
void MY_OPERATOR::process(uint32_t idx) {}
void MY_OPERATOR::process(Tuple & tuple, uint32_t port) {}
void MY_OPERATOR::process(Tuple const & tuple, uint32_t port) {}
void MY_OPERATOR::process(Punctuation const & punct, uint32_t port) {}
void MY_OPERATOR::allPortsReady() {}
void MY_OPERATOR::prepareToShutdown() {}
<%SPL::CodeGen::implementationEpilogue($model);%>
SPL type | C++ type | C++ base implementation | C++ reflective type |
---|---|---|---|
boolean | SPL::boolean | bool | N/A |
blob | SPL::blob | N/A | N/A |
timestamp | SPL::timestamp | N/A | N/A |
rstring | SPL::rstring | std::string (on x86_64) __gnu_cxx::__vstring(GNU vstring) on RHEL on IBM Power Systems |
N/A |
ustring | SPL::ustring | N/A | N/A |
u?int(8|16|32|64) | SPL::u?int(8|16|32|64) | u?int(8|16|32|64)_t | N/A |
float(32|64) | SPL::float(32|64) | (float|double) | N/A |
decimal(32|64|128) | SPL::decimal(32|64|128) | std::decimal::decimal(32|64|128) | N/A |
complex(32|64) | SPL::complex(32|64) | std::complex<float(32|64)> | N/A |
list<T> | SPL::list<T> | std::vector<T> | SPL::List |
set<T> | SPL::set<T> | std::tr1::unordered_set<T> | SPL::Set |
map<T,K> | SPL::map<T,K> | std::tr1::unordered_map<T,K> | SPL::Map |
rstring[N] | SPL::bstring<N> | N/A | SPL::BString |
list<T>[N] | SPL::blist<T,N> | N/A | SPL::BList |
set<T>[N] | SPL::bset<T,N> | N/A | SPL::BSet |
map<T,K>[N] | SPL::bmap<T,K,N> | N/A | SPL::BMap |
tuple | generated | N/A | SPL::Tuple |
enum | generated | N/A | SPL::Enum |
XML | generated | N/A | SPL::xml |
The header and implementation templates start and end with <%...%> segments. These segments contain prologue and epilogue code generation calls, namely headerPrologue and headerEpilogue, and their implementation counterparts implementationPrologue and imlementationEpilogue. These calls are used to generate code for header file includes, operator port typedefs, inclusion guards, etc. Non-generic operator implementors might opt to use C++ compliant alternatives:
#pragma SPL_NON_GENERIC_OPERATOR_HEADER_PROLOGUE
#pragma SPL_NON_GENERIC_OPERATOR_HEADER_EPILOGUE
#pragma SPL_NON_GENERIC_OPERATOR_IMPLEMENTATION_PROLOGUE
#pragma SPL_NON_GENERIC_OPERATOR_IMPLEMENTATION_EPILOGUE
The non-generic operator prologue and epilogue pragma ensure that any errors reported during the compilation of the generated code references the code generator templates, rather than the generated code. For non-generic operators, it is most likely the wanted behavior, as the code generator template contains only C++ code. These pragma also result in generation of helper member functions to easily access operator parameters for non-generic operators, as described. In summary, a non-generic operator implementation is free of any Perl code and can work with any C++ editor.
Before you get into the details of implementing operators, cover the basics of the SPL type system mappings for C++. For instance, the process member functions associated with input tuple processing have a tuple parameter of type Tuple as shown in Figure 1. The type Tuple is part of the SPL-specific C++ types.