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);%>
MY_OPERATOR
in the code.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 |
(r|u)string |
SPL::(r|u)string |
std::string|icu::UnicodeString |
N/A |
rstring |
SPL::rstring |
std::string (on x86_64) |
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| |
SPL::decimal(32|64| |
std::decimal::decimal(32|64| |
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.