/* $Id: serialize.hh,v 1.5 2005/07/04 10:25:10 atterer Exp $ -*- C++ -*-
__ _
|_) /| Copyright (C) 2001-2002 | richard@
| \/¯| Richard Atterer | atterer.net
¯ '` ¯
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2. See
the file COPYING for details.
*/
/** @file
Convert objects into byte streams and vice versa
Classes that support serialization should implement the indicated
member functions; serialize(), unserialize() and serialSizeOf(). It
is assumed that 'byte' has been typdef'd to an unsigned type which
represents one byte.
MyClass {
template
inline Iterator serialize(Iterator i) const;
template
inline ConstIterator unserialize(ConstIterator i);
inline size_t serialSizeOf() const;
};
*/
#ifndef SERIALIZE_HH
#define SERIALIZE_HH
#include
#include /* byte, size_t */
//______________________________________________________________________
/** Store serialized object via iterator. The iterator could be byte*
or vector::iterator or SerialOstreamIterator - anything in
which you can store bytes. There must be enough room to store
serialSizeOf() bytes, implementers of serialize() need not check
this.
The implementation of serialize() must both modify i and return
its value after the last modification. */
template
inline Iterator serialize(const Object& o, Iterator i) {
return o.serialize(i);
}
/** Assign the contents of the byte stream pointed to by i to the object.
template */
template
inline ConstIterator unserialize(Object& o, ConstIterator i) {
return o.unserialize(i);
}
/** Return number of bytes needed by this object when serialized. If a
whole tree of objects is serialized, this may include the
accumulated serialized sizes of the child objects, too. */
template
inline size_t serialSizeOf(const Object& o) {
return o.serialSizeOf();
}
//______________________________________________________________________
/** Slight variation (and simplification) of std::istream_iterator and
std::ostream_iterator. You *MUST* use this when reading binary
data for (un)serializing.
The reason why the ordinary iterator does not work is that it uses
"mystream >> byteToRead" which skips over whitespace (!) - this
one uses "mystream.get(byteToRead)".
Additionally, because it makes use of peek() this implementation
allows mixing of Serial*streamIterator with calls to read() on the
respective stream, without any problems. (This does not work with
GCC's version, which uses get().) */
class SerialIstreamIterator {
public:
typedef bistream istream_type;
typedef byte value_type;
typedef const byte* pointer;
typedef const byte& reference;
SerialIstreamIterator() : stream(0), val(0) { }
SerialIstreamIterator(istream_type& s) : stream(&s), val(0) { }
SerialIstreamIterator& operator++() { stream->get(); return *this; }
SerialIstreamIterator operator++(int) {
SerialIstreamIterator i = *this; stream->get(); return i; }
reference operator*() const {
val = static_cast(stream->peek()); return val; }
pointer operator->() const {
val = static_cast(stream->peek()); return &val; }
private:
istream_type* stream;
mutable byte val;
};
//____________________
/** @see SerialIstreamIterator */
class SerialOstreamIterator {
public:
typedef bostream ostream_type;
typedef void value_type;
typedef void difference_type;
typedef void pointer;
typedef void reference;
SerialOstreamIterator(ostream_type& s) : stream(&s) { }
SerialOstreamIterator& operator=(const byte val) {
stream->put(val);
return *this;
}
SerialOstreamIterator& operator*() { return *this; }
SerialOstreamIterator& operator++() { return *this; }
SerialOstreamIterator& operator++(int) { return *this; }
private:
ostream_type* stream;
};
//______________________________________________________________________
// Serializations of common data types. Stores in little-endian.
//________________________________________
/** @name
Numeric types - append the number of bytes to use (e.g. 4 for 32-bit) */
//@{
template
inline Iterator serialize1(NumType x, Iterator i) {
*i = x & 0xff; ++i;
return i;
}
template
inline ConstIterator unserialize1(NumType& x, ConstIterator i) {
x = static_cast(*i); ++i;
return i;
}
template
inline Iterator serialize2(NumType x, Iterator i) {
*i = x & 0xff; ++i;
*i = (x >> 8) & 0xff; ++i;
return i;
}
template
inline ConstIterator unserialize2(NumType& x, ConstIterator i) {
x = static_cast(*i); ++i;
x |= static_cast(*i) << 8; ++i;
return i;
}
template
inline Iterator serialize4(NumType x, Iterator i) {
*i = x & 0xff; ++i;
*i = (x >> 8) & 0xff; ++i;
*i = (x >> 16) & 0xff; ++i;
*i = (x >> 24) & 0xff; ++i;
return i;
}
template
inline ConstIterator unserialize4(NumType& x, ConstIterator i) {
x = static_cast(*i); ++i;
x |= static_cast(*i) << 8; ++i;
x |= static_cast(*i) << 16; ++i;
x |= static_cast(*i) << 24; ++i;
return i;
}
template
inline Iterator serialize6(NumType x, Iterator i) {
*i = x & 0xff; ++i;
*i = (x >> 8) & 0xff; ++i;
*i = (x >> 16) & 0xff; ++i;
*i = (x >> 24) & 0xff; ++i;
*i = (x >> 32) & 0xff; ++i;
*i = (x >> 40) & 0xff; ++i;
return i;
}
template
inline ConstIterator unserialize6(NumType& x, ConstIterator i) {
x = static_cast(*i); ++i;
x |= static_cast(*i) << 8; ++i;
x |= static_cast(*i) << 16; ++i;
x |= static_cast(*i) << 24; ++i;
x |= static_cast(*i) << 32; ++i;
x |= static_cast(*i) << 40; ++i;
return i;
}
template
inline Iterator serialize8(NumType x, Iterator i) {
*i = x & 0xff; ++i;
*i = (x >> 8) & 0xff; ++i;
*i = (x >> 16) & 0xff; ++i;
*i = (x >> 24) & 0xff; ++i;
*i = (x >> 32) & 0xff; ++i;
*i = (x >> 40) & 0xff; ++i;
*i = (x >> 48) & 0xff; ++i;
*i = (x >> 56) & 0xff; ++i;
return i;
}
template
inline ConstIterator unserialize8(NumType& x, ConstIterator i) {
x = static_cast(*i); ++i;
x |= static_cast(*i) << 8; ++i;
x |= static_cast(*i) << 16; ++i;
x |= static_cast(*i) << 24; ++i;
x |= static_cast(*i) << 32; ++i;
x |= static_cast(*i) << 40; ++i;
x |= static_cast(*i) << 48; ++i;
x |= static_cast(*i) << 56; ++i;
return i;
}
//@}
//______________________________________________________________________
#endif