Graph serialisation

Dynamic references can be serialised, provided a few properties are known about the data structure they make up. There is no way of knowing whether standard pointer actually points to a real object, nor how many. However, since collections of objects are more conveniently handled by standard containers, and since no object can pointed to by the value 0 (or NULL), we can determine these things if the programmer follows a protocol whereby a pointer either references at a single object, or is NULL. Using a smart pointer additionally enforces this protocol. We call this the treenode or graphnode protocol, depending on whether the referenced data structure has cycles or not.

By default, packing a pointer raises an exception. However, this behavior is changed either by specifying a given type obeys the treenode or graphnode protocol using the treenode pragma or graphnode pragma respectively. Alternatively, the pack_t::ptr_flag can be set to the values TREE or GRAPH respectively.

What happens in this case, is that special graph serialisation algorithms defined in pack_graph.h are called that ensure graph objects are serialised or deserialised correctly. For deserialisation, new objects must be created to store the node contents. References to these objects are placed in the alloced member of the pack_t buffer object. These newly created objects are destroyed when the buffer object is destroyed, unless a copy of the alloced vector is made first. Conversely, the objects can be destroyed without destroying the buffer by clearing the alloced vector. Individual objects can be destroyed by simply erasing them (assuming you know which ones!).

pack_graph is a recursive depth-first algorithm, that could potentially blow up the stack if the recursion depth is not limited. The recursion limit can be specified using pack_t::recur_max. pack_graph restarts the algorithm once the recursion limit is reached.

The pack_graph algorithm can also be applied to smart pointers or other reference types. An example is the ref smart pointer provided with Classdesc. For your smart pointer class T, you will need to provide an Alloc<T> class with an operator()(pack_t* buf, T& x) that returns a newly allocated object referenced by x. The buf object is there if you wish to use the alloced mechanism.