Sending and returning custom classes

We have seen previously that all STL containers can be serialized and deserialized by Thallium. Thallium can also serialize and deserialize user-defined classes, with a little help. This help comes in the form of a serialize function template put inside the class.

3D point example

Here is an example with a point class representing a 3d point.

class point {

    private:

        double x;
        double y;
        double z;

    public:

        point(double a=0.0, double b=0.0, double c=0.0)
        : x(a), y(b), z(c) {}

        template<typename A>
        void serialize(A& ar) {
             ar & x;
             ar & y;
             ar & z;
        }
};

You will also need the class to be default-constructible.

The template parameter (A) and the function’s parameter (ar) represent an archive, from which one can serialize/deserialize data. Note that you don’t need to provide two separate functions: Thallium is smart enough to use the same serialize function for both reading and writing, depending on the context.

The serialize function calls the operator & of the archive to either write or read the class’ data members. Provided that those data members are basic types, user-defined types with a serialize method, or STL containers of a serializable type, Thallium will know how to serialize the class.

Important

Thallium needs classes used as RPC argument/response to be default-constructible (i.e. provide a constructor that takes no argument).

Asymmetric serialization

In some cases it may not be possible for the serialize function to present a symmetric behavior for reading and for writing. For instance this may happen if the deserialization function needs to allocate a pointer. In these cases, one can, instead of a serialize method, provide a save method and a load method. save will be used for serialization, load will be used for deserialization.

Reading/writing raw data

It may also be convenient to read or write raw data from/to the archive. For this, note that archive objects used for serialization provide a write method:

template<typename T> write(T* const t, std::size_t count=1)

and archive objects used for deserialization provide a read method:

template<typename T> read(T* t, std::size_t count=1)

The write method should be used only in a save template method, while the read method should be used only in a load template method.

Non-member serialization functions

In some contexts it may not be possible to add member functions to a class. In those cases, you can add serialize or load/save functions outside of the class, as follows:

template<typename A>
void serialize(A& ar, MyType& x) {
  ...
}

or

template<typename A>
void save(A& ar, const MyType& x) {
  ...
}

template<typename A>
void load(A& ar, MyType& x) {
  ...
}