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.
SPL::list extends
from std::vector and not std::list.
Furthermore, SPL::map and SPL::set extend
from std::tr1::unordered_map and std::tr1::unordered_set;
not from std::map and std::set.
SPL lists are not linked-lists. They are dynamic arrays laid out on
contiguous memory. SPL maps and sets are hash-tables, and not trees.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}.tuple<float64
value, tuple<float32 x, float32 y> pos> on its first input port. In this case,
it can access the position tuple as
follows: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();
}
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.
<< and >> operators are overloaded for the
rstring class such that the character serialization and deserialization of
rstrings use the SPL string literal format. This way any string that is
serialized to a character stream can be deserialized unambiguously. An
rstring can be cast to std::string& to get the
non-literal based serialization and deserialization behavior. For
example,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