Custom types
DataStorm supports custom user types for the following:
- Keys
- Values
- Update tags
- Key or sample filter criteria
These data values must support binary encoding to be transmitted over the wire. Keys should also support the std::ostream& operator<<
. If you intend to use regular expression filters on values, values should also support this operator.
On this page:
Binary encoding
By default, DataStorm uses the Ice encoding to transmit data values over-the-wire.
The Ice encoding supports encoding a number of C++ types out-of-the box:
unsigned char
,bool
,short
,int
,long long int
,float
,double
,std::string
std::vector<T>
where T is a type supported by the Ice encodingstd::map<K, V>
where K and V are types supported by the Ice encoding
A DataStorm application can also define data types using the Slice language. The Slice definitions can be compiled with slice2cpp to generate C++ source and header files. The generated code will contain the necessary code to allow encoding and decoding the type.
Info
The Slice generated code contains support for both the Ice for C++98 and C++11 language mappings. When used with DataStorm, you should make sure to compile the generated code with -DICE_CPP11_MAPPING
to build the C++11 language mapping generated code.
You can also provide encoding and decoding function if you don't want to rely on Slice for defining your data types. DataStorm uses the Encoder
and Decoder
templates for encoding. You will need to provide template specializations for your data type. The decoder and encoder template declarations are shown below:
template<typename T, typename Enabler=void> struct Encoder { static vector<unsigned char> encode(const T& value) noexcept; }; template<typename T, typename Enabler=void> struct Decoder { static T decode(const vector<unsigned char>& data) noexcept; };
For example, you can specialize these two templates and implement the encode and decode static methods for the chrono::system_clock::time_point
type as follow:
namespace DataStorm { template<> struct Encoder<chrono::system_clock::time_point> { static vector<unsigned char> encode(const chrono::system_clock::time_point& time) noexcept { ... } }; template<> struct Decoder<chrono::system_clock::time_point> { static chrono::system_clock::time_point decode(const vector<unsigned char>& data) noexcept { ... } }; }
DataStorm can also provide the Ice communicator to the encoding and decoding methods. If you need the Ice communicator to perform the encoding and decoding, you should instead implement the following static methods:
namespace DataStorm { template<> struct Encoder<chrono::system_clock::time_point> { static vector<unsigned char> encode(const std::shared_ptr<Ice::Communicator>& communicator, const chrono::system_clock::time_point& time) noexcept { ... } }; template<> struct Decoder<chrono::system_clock::time_point> { static chrono::system_clock::time_point decode(const std::shared_ptr<Ice::Communicator>& communicator, const vector<unsigned char>& data) noexcept { ... } }; }
Streaming operator
DataStorm uses the std::ostream& operator<<
for two purposes:
- Tracing
If you enable session or data tracing, DataStorm can print out the key values. For custom key types, if no streaming operator is provided, DataStorm will print the name of the C++ typeid and the address of the value. If you want to print out a user friendly value, you should override the streaming operator.
- Filtering
DataStorm provides a pre-defined regular expression filter. The regular expression is matched against the value transformed to a string with the streaming operator.
The streaming operator can be defined as follow:
namespace DataStorm { std::ostream& operator<<(std::ostream& os, const chrono::system_clock::time_point& t) { os << t.time_since_epoch().count(); return os; } }
Value cloning
DataStorm needs to copy values to handle partial updates. By default, values are copied using the default copy constructor. This might not always be appropriate depending on the value type. For example the value type could be a shared_ptr<T>
or a complex type that requires deep-cloning. DataStorm uses the Cloner template to perform the clone. The template declaration is shown below:
template<typename T, typename Enabler=void> struct Cloner { static T clone(const T& value) noexcept; };
You can specialize this template to implement a custom cloning for a given data type:
namespace DataStorm { template<> struct Cloner<std::shared_ptr<MyClass>> { static T clone(const std::shared_ptr<MyClass>& value) noexcept { return std::make_shared<MyClass>(value); } }; }