C++ types
C++ types in SPL are typically implemented based on the C++ standard library or other well established libraries.
In most cases, the C++ types in SPL are implemented based on commonly used C++ classes. If a C++ standard library type is available, then the SPL C++ type implementation is either a typedef of or extends from that type. Examples include SPL::rstring, which extends from std::string and SPL::complex32, which is a typedef to std::complex<SPL::float32>.
For types that are not provided by the standard library, SPL C++ types employ well established libraries. For instance, list<T> extends from std::vector<T> – part of the C++ standard library. Another example is SPL::decimal32, which is a typedef to std::decimal::decimal32 – a decimal floating point class that is provided by decNumber++ library. In other cases, SPL provides its own type implementations. Examples include SPL::blob and SPL::timestamp.
Tuples (tuple<...> in SPL) and enumerations (enum{...} in SPL) are generated types. Typedefs can be used to refer to these generated types in operator implementations. For instance, assume that an operator that receives tuples of type tuple<float32 speed, enum{UP,DOWN} dir> on its first input port. In this case, the operator has a typedef IPort0Type for the C++ class that is generated for this tuple. In general, for tuples from input port n, there is a typedef IPort<n>Type and similarly for tuples from output port n, there is a typedef OPort<n>Type. Tuples provide member constructors, getters, and setters for initialization and manipulation of tuple attributes.
Getters take the form <type> const & get_<name>() const and <type> & get_<name>().
The setters take the form void set_<name>(<type> const &).
void process(Tuple & tuple, uint32_t port) {
IPort0Type & tp = static_cast<IPort0Type &>(tuple);
float32 & speed = tp.get_speed();
IPort0Type::dir_type & dir = tp.get_dir();
if(dir==IPort0Type::dir_type::UP) ...
}
The
generated tuple classes also have typedefs for each attribute they
contain. In this example, the typedef dir_type from
the generated tuple class refers to the enumeration. In general, the
typedefs inside the generated tuple classes take the form <name>_type where <name> is
the attribute name. The generated enumeration classes provide
the same literals that appear in an SPL application's source
code. In the example, dir_type::UP is compared against
the value of the dir attribute, which is of type enum{UP,DOWN}.void process(Tuple & tuple, uint32_t port) {
IPort0Type & tp = static_cast<IPort0Type &>(tuple);
float64 & value = tp.get_value();
IPort0Type::pos_type & pos = tp.get_pos();
float32 & x = pos.get_x();
float32 & y = pos.get_y();
}
The SPL language runtime also provides reflective APIs for manipulating values of SPL types. For instance, the Tuple type that is seen as part of the process member function of the operators is a reflective type. Table 1 gives the reflective base classes for SPL C++ types. These APIs enable operator developers to write generic code for handling different types, without the need for code generation (otherwise done through Perl code generation APIs at compile time). This generic code can cost additional processing. For performance sensitive applications, use code that is type-specific.
All SPL types have << and >> operator overloads for serializing and de-serializing themselves to/from character streams. They also provide operator overloads for binary serialization and deserialization by theNetworkByteBuffer and NativeByteBuffer classes.
ostream & ostr = ...
SPL::rstring abc = "ab c";
ostr << abc; //writes: "ab c"
ostr << abc.string(); // writes: ab c
ostr << abc.c_str(); // writes: ab c
ostr << static_cast<std::string&>(abc); //writes: ab c
assert(abc[0]=='a'); // "is about serialization, not part of the content