#include <x/deserialize.H> int intvalue; std::vector<std::string> strarray; std::ifstream ifs("object.dat"); std::istreambuf_iterator<char> beg(ifs.rdbuf()), end; typedef x::deserialize::iterator<std::istreambuf_iterator<char> > deser_t; deser_t deser(beg, end); deser(intvalue); deser(strarray);
The x::deserialize
namespace
defines the
iterator
template class.
This iterator
implements an operator()
that deserializes
an object.
The parameter to this template class is the input iterator type,
std::istreambuf_iterator<char>
is the
popular choice.
The constructor
takes a reference to the beginning input iterator and an ending
input iterator.
iterator
saves a reference to both iterators, which
must exist as long as the iterator
object
itself remains in scope.
The input iterator's value type must be either
char
or
unsigned char
.
iterator::operator
()
deserializes the passed object from the byte stream.
It returns a reference to this
,
allowing for the following
shorthand:
deser(intvalue)(strarray);
An exception gets thrown if the type of objects that were serialized does not match the type of objects to deserialize (but see below).
Note that objects being deserialized must be constructed beforehand and then deserialized.
An exception gets thrown if the input iterator has reached the ending input iterator before all objects have been deserialized.
When deserializing an object, an optional second parameter to the
iterator
call sets the maximum
sequence size that will be deserialized:
std::string objname; deser(objname, 255);
If the string's size comes in to more than 255 characters, an exception gets thrown. This is used in environments where the serialized byte stream comes from an untrusted source. Normally, after receiving the sequence's size, the deserialization iterator allocates the suitable amount of memory, and this prevents an untrusted source from sending a large sequence size that allocates a huge amount of memory.
The second parameter is allowed only when the object is a container.
The serialization iterator also allows a second parameter, which is
ignored. This allows the definition of the
serialize()
template method that handles both serialization and deserialization.
When serializing, the sequence size parameter gets ignored,
when deserializing, it gets checked.
It's presumed that a thin API layer handles serialization on the untrusted source side, and provides a meaningful error path that enforces the maximum sequence size. However, since the source is untrusted, the deserialization side needs to enforce this check anyway.
class object_iter; class Aobject { // ... public: Aobject(object_iter &); }; class Bobject; class Bobject_wrapper : public Bobject { // ... Bobject_wrapper(object_iter &); }; // ... class object_iter { public: template<typename iter_type> static void classlist(iter_type &iter) { iter.template serialize<Aobject>(); iter.template serialize<Bobject, Bobject_wrapper>(); } void deserialized(Aobject &obj) { // ... } void deserialized(Bobject &obj) { // ... } }; // ... object_iter any_object; deser_t::any<object_iter> any_deser(deser, any_object); any_deser();
This is an example of deserializing one of several possible objects. This is done when the serialized byte stream may contain any one of different objects, and whichever one it is needs to be deserialized and handled in some way. The steps to do this are as follows:
Define and instantiate a class called an
“object iterator class”.
The object iterator class defines an overloaded
deserialized
() method for each possible
class that may be deserialized. The object iterator class
also defines a classlist
() method.
Each class that may be deserialized must have a constructor that takes a reference to the object iterator class as a parameter. Since the same class is presumably used on the serialization side, without the deserialization object iterator class, it should also have other constructors as well, probably a default constructor explicitly defined.
Define and instantiate an any
template
class instance. The deserialization iterator class defines
an any
template class, that takes the
object iterator as the template parameter. Its constructor takes
the deserialization iterator, and the object iterator class
instance as a parameter.
Each invocation of any
's
operator()
deserializes a class from
the deserialization iterator, and invokes the appropriate
deserialized
() method in the object iterator
class.
The object iterator class instance and the deserialization iterator
must remain in scope as long as the any
instance remains in scope.
From the object iterator's class classlist() method, calls to
serialize() may also specify a second template class, which
gets instantiated instead of the class being deserialized,
when deserialization occurs. The above example results in
Bobject_wrapper
getting instantiated
when deserialize Bobject
.
Bobject_wrapper
subclasses from
Bobject
, and presumably
Bobject
's
serialize
() gets called to do the deed,
while it's Bobject_wrapper
gets instantiated.
The object iterator class's overloaded
deserialized
() may specify either
Bobject_wrapper
or
Bobject
.
More specifically, the requirements of an object iterator class are:
A template
function named classlist
()
(see below).
When any
()
determines which object should be deserialized,
the templated object gets constructed on the stack.
If the second class was given in classlist
,
the second class gets constructed instead of the first one.
The constructed object's serialize
() method
gets invoked.
An overloaded
deserialized
() method (which can be a
template), one for each class iterated in the
classlist
() method.
If two classes were specified in the
classlist
() method's iteration, either
the first class or the second may be used for
deserialized
().
any
() constructs the appropriate object,
and invokes the appropriate
deserialized
() method. The deserialized
object goes out of scope before any
() returns.
The object iterator's
classlist
template function takes one or two
template classes as a parameter, and one argument, a reference
to the template class.
The template class instance that's passed as an argument to
classlist
()
will have a public member template function,
serialize
().
classlist
() should iterate over a list of
all classes that may be deserialized, by invoking
the passed iterator's serialize
() template method.
The previous example iterates over two classes
Aobject
and
Bobject
/Bobject_wrapper
,
and shows the expected implementation
pattern for any number of classes that may be deserialized.