Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

wvserialize.h

Go to the documentation of this file.
00001 /* -*- Mode: C++ -*-
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  *
00005  * Code to serialize objects into WvBufs, and more code to read WvBufs and
00006  * construct objects from them.
00007  */
00008 #ifndef __WVSERIALIZE_H
00009 #define __WVSERIALIZE_H
00010 
00011 #include "wvbuf.h"
00012 #include <stdint.h>
00013 #ifndef _WIN32
00014 #include <netinet/in.h>
00015 #endif
00016 
00017 /**
00018  * Encode an object as an array of bytes and put it into a WvBuf.  This
00019  * function just calls an overloaded _wv_serialize() function.  There was
00020  * really no need for a template here at all, except for symmetry with
00021  * wv_deserialize() which does need one.
00022  */
00023 template <typename T>
00024 inline void wv_serialize(WvBuf &buf, const T &t)
00025 {
00026     _wv_serialize(buf, t);
00027 }
00028 
00029 
00030 /**
00031  * This function shouldn't be necessary at all, but using it makes totally
00032  * insane assembler errors go away (gcc 2.95.4, glibc 2.3.1).
00033  */
00034 inline int32_t _wv_htonl(int32_t i)
00035 {
00036     return htonl(i);
00037 }
00038 
00039 
00040 
00041 /**
00042  * A helper function that serializes different types of integers.  Since
00043  * it's inlined, the "if" is actually executed at compile time, so don't
00044  * worry.
00045  * 
00046  * The clever part: it doesn't really matter what size an 'int' or a 'long'
00047  * is, as long as it's one of the sizes supported by this function.  If an
00048  * int is 32 bits, we'll use the 32-bit serializer... and so on.
00049  */
00050 template <typename T>
00051 void wv_serialize_scalar(WvBuf &buf, const T t)
00052 {
00053     if (sizeof(T) == 8)
00054     {
00055         // FIXME: don't know a portable way to convert this to network
00056         // byte order!
00057         buf.put(&t, 8);
00058     }
00059     else if (sizeof(T) == 4)
00060     {
00061         int32_t i = _wv_htonl(t);
00062         buf.put(&i, 4);
00063     }
00064     else if (sizeof(T) == 2)
00065     {
00066         int32_t i = htons(t);
00067         buf.put(&i, 2);
00068     }
00069     else if (sizeof(T) == 1)
00070         buf.put(&t, 1);
00071     else
00072         assert(0);
00073 }
00074 
00075 inline void _wv_serialize(WvBuf &buf, long long i)
00076     { wv_serialize_scalar(buf, i); }
00077 inline void _wv_serialize(WvBuf &buf, unsigned long long i)
00078     { wv_serialize_scalar(buf, i); }
00079 inline void _wv_serialize(WvBuf &buf, long i)
00080     { wv_serialize_scalar(buf, i); }
00081 inline void _wv_serialize(WvBuf &buf, unsigned long i)
00082     { wv_serialize_scalar(buf, i); }
00083 inline void _wv_serialize(WvBuf &buf, int i)
00084     { wv_serialize_scalar(buf, i); }
00085 inline void _wv_serialize(WvBuf &buf, unsigned int i)
00086     { wv_serialize_scalar(buf, i); }
00087 inline void _wv_serialize(WvBuf &buf, short i)
00088     { wv_serialize_scalar(buf, i); }
00089 inline void _wv_serialize(WvBuf &buf, unsigned short i)
00090     { wv_serialize_scalar(buf, i); }
00091 inline void _wv_serialize(WvBuf &buf, bool i)
00092     { wv_serialize_scalar(buf, i); }
00093 
00094 /** Note: char != signed char for purposes of function overloading! */
00095 inline void _wv_serialize(WvBuf &buf, char i)
00096     { wv_serialize_scalar(buf, i); }
00097 inline void _wv_serialize(WvBuf &buf, signed char i)
00098     { wv_serialize_scalar(buf, i); }
00099 inline void _wv_serialize(WvBuf &buf, unsigned char i)
00100     { wv_serialize_scalar(buf, i); }
00101 
00102 
00103 /**
00104  * Serialize a WvString. The string serializer is guaranteed to not insert
00105  * any nuls (character 0) into the output stream except for the
00106  * string-terminating one, which is always present.  This makes
00107  * deserialization easy.
00108  */
00109 inline void _wv_serialize(WvBuf &buf, WvStringParm s)
00110 {
00111     if (!s.isnull())
00112         buf.putstr(s);
00113     buf.put("", 1); // terminating nul
00114 }
00115 
00116 
00117 /**
00118  * Serialize a WvBuf.  This is handier than it sounds, because then
00119  * WvGdbmHash's value can be a WvBuf.
00120  */
00121 inline void _wv_serialize(WvBuf &buf, const WvBuf &inbuf)
00122 {
00123     wv_serialize(buf, inbuf.used());
00124     buf.put(const_cast<WvBuf *>(&inbuf)->peek(0, inbuf.used()), inbuf.used());
00125 }
00126 
00127 
00128 /**
00129  * Serialize a list of serializable things.
00130  * 
00131  * Oh boy - I think I'm having a bit too much fun.
00132  */
00133 template <typename T>
00134 void _wv_serialize(WvBuf &buf, const WvList<T> &list)
00135 {
00136     // save the number of elements
00137     _wv_serialize(buf, (size_t)list.count());
00138     
00139     // save the elements
00140     typename WvList<T>::Iter i(list);
00141     for (i.rewind(); i.next(); )
00142         _wv_serialize(buf, *i);
00143 }
00144 
00145 
00146 
00147 /** Deserialize an object.  See wv_deserialize(). */
00148 template <typename T>
00149     T _wv_deserialize(WvBuf &buf);
00150 
00151 
00152 /**
00153  * Deserialize a complex templated object.  See wv_deserialize().
00154  * 
00155  * This class is needed because partial template specialization only works
00156  * on classes, not on functions.  So in order to define a generic deserializer
00157  * for, say, WvList<T>, we have to have a class with a member function.  Sigh.
00158  */
00159 template <typename T>
00160 class WvDeserialize
00161 {
00162 public:
00163     static T go(WvBuf &buf)
00164         { return _wv_deserialize<T>(buf); }
00165 };
00166 
00167 
00168 /**
00169  * If there's a deserializer for type "T", this will make a default
00170  * deserializer for type "T *"; that is, it'll allocate the new object
00171  * dynamically and you'll have to free it after.
00172  * 
00173  * This helps when you want to assume *all* deserializers return pointers
00174  * that you need to delete later.
00175  * 
00176  * FIXME: this class takes precedence over *specialized* _wv_deserialize()
00177  * functions for pointers!  Pointer-based deserializers need to be classes
00178  * too until this is resolved.
00179  */
00180 // note: this has to be a class because we use partial template
00181 // specialization, which doesn't work on functions.
00182 template <typename T>
00183 class WvDeserialize<T *>
00184 {
00185 public:
00186     static T *go(WvBuf &buf)
00187         { return new T(_wv_deserialize<T>(buf)); }
00188 };
00189 
00190 
00191 
00192 /**
00193  * Deserialize an object: read bytes from a buffer, and return an object
00194  * constructed from that.
00195  * 
00196  * Note that there is no default deserializer.  You have to specialize this
00197  * template for every data type you might want to deserialize.  We do define
00198  * some for a few standard C types.
00199  * 
00200  * Implementation note:
00201  * If you define a deserializer for your own type, name it _wv_deserialize()
00202  * (with the underscore).  If you're unlucky, you may need to define a
00203  * WvDeserialize class instead.
00204  * 
00205  * Note that if you have a data structure, you probably want to
00206  * wv_deserialize<MyType *>(buf) instead of wv_deserialize<MyType>(buf) to
00207  * avoid extra copies.  You'll have to define _wv_deserialize() appropriately,
00208  * of course.  Pointer-based _wv_deserialize() functions allocate memory,
00209  * so you'll have to 'delete' the returned object yourself.
00210  */
00211 template <typename T>
00212 inline T wv_deserialize(WvBuf &buf)
00213 {
00214     return WvDeserialize<T>::go(buf);
00215 }
00216 
00217 
00218 /**
00219  * This function shouldn't be necessary at all, but using it makes totally
00220  * insane assembler errors go away (gcc 2.95.4, glibc 2.3.1).
00221  */
00222 inline int32_t _wv_ntohl(int32_t i)
00223 {
00224     return ntohl(i);
00225 }
00226 
00227 
00228 /**
00229  * A helper function that deserializes different types of integers.  Since
00230  * it's inlined, the "if" is actually executed at compile time, so don't
00231  * worry.
00232  */
00233 template <typename T>
00234 inline T wv_deserialize_scalar(WvBuf &buf)
00235 {
00236     if (buf.used() < sizeof(T))
00237         return 0;
00238     
00239     if (sizeof(T) == 8)
00240     {
00241         // FIXME: don't know a portable way to convert this to network
00242         // byte order!
00243         return (T) *(int64_t *)buf.get(8);
00244     }
00245     else if (sizeof(T) == 4)
00246         return (T) _wv_ntohl(*(int32_t *)buf.get(4));
00247     else if (sizeof(T) == 2)
00248         return (T) ntohs(*(int16_t *)buf.get(2));
00249     else if (sizeof(T) == 1)
00250         return (T) *(int8_t *)buf.get(1);
00251     else
00252         assert(0);
00253 }
00254 
00255 template <typename T>
00256 inline T xwv_deserialize_scalar(WvBuf &buf)
00257 {
00258     return 0;
00259 }
00260 
00261 template <>
00262     inline long long _wv_deserialize<long long>(WvBuf &buf)
00263     { return wv_deserialize_scalar<long long>(buf); }
00264 template <> 
00265     inline unsigned long long _wv_deserialize<unsigned long long>(WvBuf &buf)
00266     { return wv_deserialize_scalar<unsigned long long>(buf); }
00267 template <>
00268     inline long _wv_deserialize<long>(WvBuf &buf)
00269     { return wv_deserialize_scalar<long>(buf); }
00270 template <> 
00271     inline unsigned long _wv_deserialize<unsigned long>(WvBuf &buf)
00272     { return wv_deserialize_scalar<unsigned long>(buf); }
00273 template <>
00274     inline int _wv_deserialize<int>(WvBuf &buf)
00275     { return wv_deserialize_scalar<int>(buf); }
00276 template <> 
00277     inline unsigned int _wv_deserialize<unsigned int>(WvBuf &buf)
00278     { return wv_deserialize_scalar<unsigned int>(buf); }
00279 template <>
00280     inline short _wv_deserialize<short>(WvBuf &buf)
00281     { return wv_deserialize_scalar<short>(buf); }
00282 template <> 
00283     inline unsigned short _wv_deserialize<unsigned short>(WvBuf &buf)
00284     { return wv_deserialize_scalar<unsigned short>(buf); }
00285 template <> 
00286     inline bool _wv_deserialize<bool>(WvBuf &buf)
00287     { return wv_deserialize_scalar<bool>(buf); }
00288 template <>
00289     inline char _wv_deserialize<char>(WvBuf &buf)
00290     { return wv_deserialize_scalar<char>(buf); }
00291 template <> 
00292     inline signed char _wv_deserialize<signed char>(WvBuf &buf)
00293     { return wv_deserialize_scalar<signed char>(buf); }
00294 template <> 
00295     inline unsigned char _wv_deserialize<unsigned char>(WvBuf &buf)
00296     { return wv_deserialize_scalar<unsigned char>(buf); }
00297 
00298 /**
00299  * Deserialize a WvString.  Stops at (and includes) the terminating nul
00300  * (zero) character.  Serialized WvStrings are guaranteed not to contain nul
00301  * except as the last character.
00302  */
00303 template <>
00304 extern WvString _wv_deserialize<WvString>(WvBuf &buf);
00305 
00306 
00307 /** Deserialize a WvBuf. */
00308 // FIXME: it should be possible to do this without using a class!
00309 template <>
00310 class WvDeserialize<WvBuf *>
00311 {
00312 public:
00313     static inline WvBuf *go(WvBuf &buf)
00314     {
00315         size_t len = wv_deserialize<size_t>(buf);
00316         WvBuf *outbuf = new WvInPlaceBuf(new char[len], 0, len, true);
00317         outbuf->merge(buf, len);
00318         return outbuf;
00319     }
00320 };
00321 
00322 
00323 /** Deserialize a list of serializable things. */
00324 template <typename T>
00325 class WvDeserialize<WvList<T> *>
00326 {
00327 public:
00328     static WvList<T> *go(WvBuf &buf)
00329     {
00330         WvList<T> *list = new WvList<T>;
00331         size_t nelems = wv_deserialize<size_t>(buf);
00332         
00333         for (size_t count = 0; count < nelems; count++)
00334         {
00335             T t = wv_deserialize<T>(buf);
00336             list->append(new T(t), true);
00337         }
00338         
00339         return list;
00340     }
00341 };
00342 
00343 
00344 #endif // __WVSERIALIZE_H

Generated on Sat Mar 13 14:55:53 2004 for WvStreams by doxygen 1.3.6-20040222