Branch data Line data Source code
1 : : // $Id: SerialObj.h 6752 2009-06-14 04:24:52Z vern $
2 : : //
3 : : // Infrastructure for serializable objects.
4 : : //
5 : : // How to make objects of class Foo serializable:
6 : : //
7 : : // 1. Derive Foo (directly or indirectly) from SerialObj.
8 : : // 2. Add a SER_FOO constant to SerialTypes below.
9 : : // 3. Add DECLARE_SERIAL(Foo) into class definition.
10 : : // 4. Add a (preferably protected) default ctor if it doesn't already exist.
11 : : // 5. For non-abstract classes, add IMPLEMENT_SERIAL(Foo, SER_FOO) to *.cc
12 : : // 6. Add two methods like this to *.cc (keep names of arguments!)
13 : : //
14 : : // bool Foo::DoSerialize(SerialInfo* info) const
15 : : // {
16 : : // DO_SERIALIZE(SER_FOO, ParentClassOfFoo);
17 : : // <... serialize class members via methods in Serializer ...>
18 : : // return true if everything ok;
19 : : // }
20 : : //
21 : : // bool Foo::DoUnserialize(UnserialInfo* info)
22 : : // {
23 : : // DO_UNSERIALIZE(ParentClassOfFoo);
24 : : // <... unserialize class members via methods in Serializer ...>
25 : : // return true if everything ok;
26 : : // }
27 : : //
28 : : // (7. If no parent class of Foo already contains Serialize()/Unserialize()
29 : : // methods, these need to be added somewhere too. But most of the various
30 : : // parts of the class hierarchy already have them.)
31 : :
32 : :
33 : : #ifndef SERIALOBJ_H
34 : : #define SERIALOBJ_H
35 : :
36 : : #include <map>
37 : : #include <util.h>
38 : :
39 : : #include "DebugLogger.h"
40 : : #include "Continuation.h"
41 : : #include "SerialTypes.h"
42 : : #include "config.h"
43 : :
44 : : #if SIZEOF_LONG_LONG < 8
45 : : # error "Serialization requires that sizeof(long long) is at least 8. (Remove this message only if you know what you're doing.)"
46 : : #endif
47 : :
48 : : class Serializer;
49 : : class SerialInfo;
50 : : class UnserialInfo;
51 : : class SerializationCache;
52 : :
53 : : // Per-process unique ID.
54 : : class TransientID {
55 : : public:
56 : 2028196 : TransientID() { id = ++counter; }
57 : :
58 : : typedef unsigned long long ID;
59 : 279 : ID Value() const { return id; }
60 : :
61 : : private:
62 : : ID id;
63 : : static ID counter;
64 : : };
65 : :
66 : : // Abstract base class for serializable objects.
67 : 903706 : class SerialObj {
68 : : public:
69 [ # # ][ # # ]: 0 : virtual ~SerialObj() { }
70 : :
71 : 0 : virtual const TransientID* GetTID() const { return 0; }
72 : :
73 : 0 : virtual SerialType GetSerialType() const { return 0; }
74 : :
75 : 65 : bool IsBroObj() const { return IsBroObj(GetSerialType()); }
76 : 32 : bool IsCacheStable() const { return IsCacheStable(GetSerialType()); }
77 : :
78 : : static const uint64 NEVER = 0;
79 : : static const uint64 ALWAYS = 1;
80 : :
81 : : // Returns time of last modification. This "time" is a monotonically
82 : : // increasing counter which is incremented each time a modification is
83 : : // performed (more precisely: each time an object is modified which
84 : : // returns something different than NEVER). Such times can thus be
85 : : // compared to see whether some modification took place before another.
86 : : //
87 : : // There are two special values:
88 : : // NEVER: This object will never change.
89 : : // ALWAYS: Always consider this object as changed, i.e., don't
90 : : // cache it.
91 : 42 : virtual uint64 LastModified() const { return NEVER; }
92 : :
93 : : // Instantiate an object of the given type. Return nil
94 : : // if unknown.
95 : : static SerialObj* Instantiate(SerialType type);
96 : :
97 : : static const char* ClassName(SerialType type);
98 : :
99 : : // Associate a "factory" function with the given type.
100 : : // A factory is a class or function that creates instances
101 : : // of a certain type.
102 : :
103 : : typedef SerialObj* (*FactoryFunc)();
104 : : static void Register(SerialType type, FactoryFunc f,
105 : : const char* class_name);
106 : :
107 : 65 : static bool IsBroObj(SerialType type)
108 : 65 : { return type & SER_IS_BRO_OBJ; }
109 : :
110 : 32 : static bool IsCacheStable(SerialType type)
111 : 32 : { return type & SER_IS_CACHE_STABLE; }
112 : :
113 : 0 : static bool CheckTypes(SerialType type1, SerialType type2)
114 : : { return (type1 & SER_TYPE_MASK_PARENT) ==
115 : 0 : (type2 & SER_TYPE_MASK_PARENT); }
116 : :
117 : : protected:
118 : : friend class SerializationCache;
119 : :
120 : 1620695 : SerialObj()
121 : 1620695 : {
122 : : #ifdef DEBUG
123 : 1620695 : serial_type = 0;
124 : : #endif
125 : 1620695 : }
126 : :
127 : : // Serializes this object. If info->cache is false, we can use
128 : : // DECLARE_NON_CACHEABLE_SERIAL (instead of DECLARE_SERIAL) which
129 : : // avoids storing a per-object id.
130 : : bool Serialize(SerialInfo* info) const;
131 : :
132 : : // Unserializes next object.
133 : : static SerialObj* Unserialize(UnserialInfo* info,
134 : : SerialType type);
135 : :
136 : : virtual bool DoSerialize(SerialInfo* info) const;
137 : : virtual bool DoUnserialize(UnserialInfo* info);
138 : :
139 : : typedef std::map<SerialType, FactoryFunc> FactoryMap;
140 : : static FactoryMap* factories;
141 : :
142 : : typedef std::map<SerialType, const char*> ClassNameMap;
143 : : static ClassNameMap* names;
144 : :
145 : : static uint64 time_counter;
146 : 291575 : static uint64 IncreaseTimeCounter() { return ++time_counter; }
147 : 65 : static uint64 GetTimeCounter() { return time_counter; }
148 : :
149 : : #ifdef DEBUG
150 : : SerialType serial_type;
151 : : #endif
152 : : };
153 : :
154 : : // A class that registers a factory function upon instantiation.
155 : : class SerialTypeRegistrator {
156 : : public:
157 : : SerialTypeRegistrator(SerialType type, SerialObj::FactoryFunc func,
158 : 288 : const char* class_name)
159 : : {
160 : 288 : SerialObj::Register(type, func, class_name);
161 : 288 : }
162 : : };
163 : :
164 : :
165 : : // Macro helpers.
166 : :
167 : : #define DECLARE_ABSTRACT_SERIAL(classname) \
168 : : virtual bool DoSerialize(SerialInfo*) const; \
169 : : virtual bool DoUnserialize(UnserialInfo*); \
170 : :
171 : : #define DECLARE_SERIAL(classname) \
172 : : static classname* Instantiate(); \
173 : : static SerialTypeRegistrator register_type; \
174 : : virtual bool DoSerialize(SerialInfo*) const; \
175 : : virtual bool DoUnserialize(UnserialInfo*); \
176 : : virtual const TransientID* GetTID() const { return &tid; } \
177 : : virtual SerialType GetSerialType() const; \
178 : : TransientID tid;
179 : :
180 : : // Only needed (and usable) for non-abstract classes.
181 : : #define IMPLEMENT_SERIAL(classname, classtype) \
182 : : SerialTypeRegistrator classname::register_type(classtype, \
183 : : FactoryFunc(&classname::Instantiate), #classname); \
184 : : SerialType classname::GetSerialType() const { return classtype; }; \
185 : : classname* classname::Instantiate() { return new classname(); } \
186 : :
187 : : // Pushes debug level on instantiation and pops when it goes out of scope.
188 : : class AutoPush {
189 : : public:
190 : 121 : AutoPush() { DBG_PUSH(DBG_SERIAL); }
191 : 121 : ~AutoPush() { DBG_POP(DBG_SERIAL); }
192 : : };
193 : :
194 : : // Note that by default we disable suspending. Use DO_SERIALIZE_WITH_SUSPEND
195 : : // to enable, but be careful to make sure that whomever calls us is aware of
196 : : // the fact (or has already disabled suspension itself).
197 : : #define DO_SERIALIZE(classtype, super) \
198 : : DBG_LOG(DBG_SERIAL, __PRETTY_FUNCTION__); \
199 : : if ( info->type == SER_NONE ) \
200 : : info->type = classtype; \
201 : : DisableSuspend suspend(info); \
202 : : AutoPush auto_push; \
203 : : if ( ! super::DoSerialize(info) ) \
204 : : return false;
205 : :
206 : : // Unfortunately, this is getting quite long. :-(
207 : : #define DO_SERIALIZE_WITH_SUSPEND(classtype, super) \
208 : : DBG_LOG(DBG_SERIAL, __PRETTY_FUNCTION__); \
209 : : if ( info->type == SER_NONE ) \
210 : : info->type = classtype; \
211 : : AutoPush auto_push; \
212 : : \
213 : : bool call_super = info->cont.NewInstance(); \
214 : : \
215 : : if ( info->cont.ChildSuspended() ) \
216 : : { \
217 : : void* user_ptr = info->cont.RestoreState(); \
218 : : if ( user_ptr == &call_super ) \
219 : : call_super = true; \
220 : : } \
221 : : \
222 : : if ( call_super ) \
223 : : { \
224 : : info->cont.SaveState(&call_super); \
225 : : info->cont.SaveContext(); \
226 : : bool result = super::DoSerialize(info); \
227 : : info->cont.RestoreContext(); \
228 : : if ( ! result ) \
229 : : return false; \
230 : : if ( info->cont.ChildSuspended() ) \
231 : : return true; \
232 : : info->cont.SaveState(0); \
233 : : } \
234 : :
235 : : #define DO_UNSERIALIZE(super) \
236 : : DBG_LOG(DBG_SERIAL, __PRETTY_FUNCTION__); \
237 : : AutoPush auto_push; \
238 : : if ( ! super::DoUnserialize(info) ) \
239 : : return false;
240 : :
241 : : #define SERIALIZE(x) \
242 : : info->s->Write(x, #x)
243 : :
244 : : #define SERIALIZE_STR(x, y) \
245 : : info->s->Write(x, y, #x)
246 : :
247 : : #define SERIALIZE_BIT(bit) \
248 : : info->s->Write(bool(bit), #bit)
249 : :
250 : : #define UNSERIALIZE(x) \
251 : : info->s->Read(x, #x)
252 : :
253 : : #define UNSERIALIZE_STR(x, y) \
254 : : info->s->Read(x, y, #x)
255 : :
256 : : #define UNSERIALIZE_BIT(bit) \
257 : : { \
258 : : bool tmp; \
259 : : if ( ! info->s->Read(&tmp, #bit) ) \
260 : : return false; \
261 : : bit = (unsigned int) tmp; \
262 : : }
263 : :
264 : : // Some helpers for pointers which may be nil.
265 : : #define SERIALIZE_OPTIONAL(ptr) \
266 : : { \
267 : : if ( ptr ) \
268 : : { \
269 : : if ( ! info->cont.ChildSuspended() ) \
270 : : if ( ! info->s->Write(true, "has_" #ptr) ) \
271 : : return false; \
272 : : \
273 : : info->cont.SaveContext(); \
274 : : bool result = ptr->Serialize(info); \
275 : : info->cont.RestoreContext(); \
276 : : if ( ! result ) \
277 : : return false; \
278 : : \
279 : : if ( info->cont.ChildSuspended() ) \
280 : : return true; \
281 : : } \
282 : : \
283 : : else if ( ! info->s->Write(false, "has_" #ptr) ) \
284 : : return false; \
285 : : }
286 : :
287 : : #define SERIALIZE_OPTIONAL_STR(str) \
288 : : { \
289 : : if ( str ) \
290 : : { \
291 : : if ( ! (info->s->Write(true, "has_" #str) && info->s->Write(str, "str")) ) \
292 : : return false; \
293 : : } \
294 : : \
295 : : else if ( ! info->s->Write(false, "has_" #str) ) \
296 : : return false; \
297 : : }
298 : :
299 : : #define UNSERIALIZE_OPTIONAL(dst, unserialize) \
300 : : { \
301 : : bool has_it; \
302 : : if ( ! info->s->Read(&has_it, "has_" #dst) ) \
303 : : return false; \
304 : : \
305 : : if ( has_it ) \
306 : : { \
307 : : dst = unserialize; \
308 : : if ( ! dst ) \
309 : : return false; \
310 : : } \
311 : : \
312 : : else \
313 : : dst = 0; \
314 : : }
315 : :
316 : : #define UNSERIALIZE_OPTIONAL_STR(dst) \
317 : : { \
318 : : bool has_it; \
319 : : if ( ! info->s->Read(&has_it, "has_" #dst) ) \
320 : : return false; \
321 : : \
322 : : if ( has_it ) \
323 : : { \
324 : : info->s->Read(&dst, 0, "has_" #dst); \
325 : : if ( ! dst ) \
326 : : return false; \
327 : : } \
328 : : \
329 : : else \
330 : : dst = 0; \
331 : : }
332 : :
333 : : #define UNSERIALIZE_OPTIONAL_STATIC(dst, unserialize, del) \
334 : : { \
335 : : bool has_it; \
336 : : if ( ! info->s->Read(&has_it, "has_" #dst) ) \
337 : : { \
338 : : delete del; \
339 : : return 0; \
340 : : } \
341 : : \
342 : : if ( has_it ) \
343 : : { \
344 : : dst = unserialize; \
345 : : if ( ! dst ) \
346 : : { \
347 : : delete del; \
348 : : return 0; \
349 : : } \
350 : : } \
351 : : \
352 : : else \
353 : : dst = 0; \
354 : : }
355 : :
356 : : #endif
|