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 Tue Oct 5 01:09:20 2004 for WvStreams by doxygen 1.3.7