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