Inspirel banner

Programming Distributed Systems with YAMI4

3.5.2 C++

Simple values (boolean, integer, long and double) can be set with a single operation:

params.set_integer("age", 25);

Above, a new entry named ``age'' is created (or replaces the existing one with the same name) and an integer value 25 is set as its content.

String values are also handled directly and both char pointers and std::string objects can be used:

params.set_string("first_name", "John");

The binary values are handled with the pair of void * and std::size_t to describe the data buffer:

void * song_buffer = ...;
std::size_t song_size = ...;

params.set_binary("favorite_song", song_buffer, song_size);

In both string and binary cases, the arrays are copied into the internal storage of the parameters object, so that the original values that were provided by the user are no longer referenced.

For performance-oriented applications there is a variant of the above methods that only sets buffer references without actually copying the data - the function names have the _shallow postfix, for example set_string_shallow and set_binary_shallow:

std::string name = "John";
params.set_string_shallow(
    "first_name", name.data(), name.size());

Above, the pointer to the name's buffer is set in the parameters object without actually copying the string value, which in the case of very long strings can offer substantial performance improvements. These improvement opportunities come at the price of more involved lifetime management at the user side, as the provided buffer has to be kept alive and available as long as it is referenced by the parameters object. In practice, the original buffer (in the above example it is the content of the name variable) can be destroyed or reused after the parameters object is serialized, which happens when the parameters object is used for message sending or reply.

Arrays of simple types are handled similarly to binary buffers - that is, pointer to relevant type and std::size_t are used as array descriptors. Similarly, the ``shallow'' versions are provided as well.

For example:

std::vector<int> my_numbers = ...;

params.set_integer_array("favorite_numbers",
    &my_numbers[0], my_numbers.size());

// or, to avoid copying:
params.set_integer_array_shallow("favorite_numbers",
    &my_numbers[0], my_numbers.size());

Arrays of strings do not follow the same strategy. The reason for this is that arrays of strings can be ``ragged'' - that is, the lengths of individual array elements might be different - and they are implemented with indirection. The string array is set in two phases - it has to be created and then populated with values, as in the following example:

params.create_string_array("friends", 3);

params.set_string_in_array("friends", 0, "Alice");
params.set_string_in_array("friends", 1, "Bob");
params.set_string_in_array("friends", 2, "Nicole");

After the string array is created within the parameters object, it has the requested length, but all array elements are empty. The individual elements need to be set separately and the element is identified by both the array entry name (``friends'' above) and the array index, starting from 0. Each entry can have different length.

Arrays of binary values are handled in a similar way, with void * and std::size_t pairs used for buffer description.

Nested parameters allow to build some form of hierarchic data structures. Nested parameters objects are created within existing parameters objects:

parameters nested(params.create_nested_parameters("address"));

The nested object declared above is not a stand-alone object, but refers to the nested entry in the params object. This means that both objects are coupled and care should be taken so that the containing object (params) is not destroyed before the one that refers to its internals (nested) - it is recommended to use scoping to ensure proper lifetime management. Since both params and nested know their relation, the contained object will be cleaned up only as part of the finalization of the params object.

The nested object declared above can be used just as any regular parameters object, for example:

nested.set_string("street", "Flowery");
nested.set_integer("house_number", 17);

Similar rules apply for nested parameters arrays, which are also created within already existing parameters objects and then accessed on individual basis.

All the example statements in this section filled a single parameters object with six entries (``age'', ``first_name'', ``favorite_song'', ``favorite_numbers'' ``friends'' and ``address''), one them being an array with 3 elements and one being a nested parameters with 2 entries.