LCOV - code coverage report
Current view: top level - src - SerialObj.h (source / functions) Hit Total Coverage
Test: app.info Lines: 21 26 80.8 %
Date: 2010-12-13 Functions: 15 21 71.4 %
Branches: 0 4 0.0 %

           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

Generated by: LCOV version 1.8