mirror of
https://github.com/zeek/zeek.git
synced 2025-10-06 16:48:19 +00:00
Initial import of svn+ssh:://svn.icir.org/bro/trunk/bro as of r7088
This commit is contained in:
commit
61757ac78b
1383 changed files with 380824 additions and 0 deletions
356
src/SerialObj.h
Normal file
356
src/SerialObj.h
Normal file
|
@ -0,0 +1,356 @@
|
|||
// $Id: SerialObj.h 6752 2009-06-14 04:24:52Z vern $
|
||||
//
|
||||
// Infrastructure for serializable objects.
|
||||
//
|
||||
// How to make objects of class Foo serializable:
|
||||
//
|
||||
// 1. Derive Foo (directly or indirectly) from SerialObj.
|
||||
// 2. Add a SER_FOO constant to SerialTypes below.
|
||||
// 3. Add DECLARE_SERIAL(Foo) into class definition.
|
||||
// 4. Add a (preferably protected) default ctor if it doesn't already exist.
|
||||
// 5. For non-abstract classes, add IMPLEMENT_SERIAL(Foo, SER_FOO) to *.cc
|
||||
// 6. Add two methods like this to *.cc (keep names of arguments!)
|
||||
//
|
||||
// bool Foo::DoSerialize(SerialInfo* info) const
|
||||
// {
|
||||
// DO_SERIALIZE(SER_FOO, ParentClassOfFoo);
|
||||
// <... serialize class members via methods in Serializer ...>
|
||||
// return true if everything ok;
|
||||
// }
|
||||
//
|
||||
// bool Foo::DoUnserialize(UnserialInfo* info)
|
||||
// {
|
||||
// DO_UNSERIALIZE(ParentClassOfFoo);
|
||||
// <... unserialize class members via methods in Serializer ...>
|
||||
// return true if everything ok;
|
||||
// }
|
||||
//
|
||||
// (7. If no parent class of Foo already contains Serialize()/Unserialize()
|
||||
// methods, these need to be added somewhere too. But most of the various
|
||||
// parts of the class hierarchy already have them.)
|
||||
|
||||
|
||||
#ifndef SERIALOBJ_H
|
||||
#define SERIALOBJ_H
|
||||
|
||||
#include <map>
|
||||
#include <util.h>
|
||||
|
||||
#include "DebugLogger.h"
|
||||
#include "Continuation.h"
|
||||
#include "SerialTypes.h"
|
||||
#include "config.h"
|
||||
|
||||
#if SIZEOF_LONG_LONG < 8
|
||||
# error "Serialization requires that sizeof(long long) is at least 8. (Remove this message only if you know what you're doing.)"
|
||||
#endif
|
||||
|
||||
class Serializer;
|
||||
class SerialInfo;
|
||||
class UnserialInfo;
|
||||
class SerializationCache;
|
||||
|
||||
// Per-process unique ID.
|
||||
class TransientID {
|
||||
public:
|
||||
TransientID() { id = ++counter; }
|
||||
|
||||
typedef unsigned long long ID;
|
||||
ID Value() const { return id; }
|
||||
|
||||
private:
|
||||
ID id;
|
||||
static ID counter;
|
||||
};
|
||||
|
||||
// Abstract base class for serializable objects.
|
||||
class SerialObj {
|
||||
public:
|
||||
virtual ~SerialObj() { }
|
||||
|
||||
virtual const TransientID* GetTID() const { return 0; }
|
||||
|
||||
virtual SerialType GetSerialType() const { return 0; }
|
||||
|
||||
bool IsBroObj() const { return IsBroObj(GetSerialType()); }
|
||||
bool IsCacheStable() const { return IsCacheStable(GetSerialType()); }
|
||||
|
||||
static const uint64 NEVER = 0;
|
||||
static const uint64 ALWAYS = 1;
|
||||
|
||||
// Returns time of last modification. This "time" is a monotonically
|
||||
// increasing counter which is incremented each time a modification is
|
||||
// performed (more precisely: each time an object is modified which
|
||||
// returns something different than NEVER). Such times can thus be
|
||||
// compared to see whether some modification took place before another.
|
||||
//
|
||||
// There are two special values:
|
||||
// NEVER: This object will never change.
|
||||
// ALWAYS: Always consider this object as changed, i.e., don't
|
||||
// cache it.
|
||||
virtual uint64 LastModified() const { return NEVER; }
|
||||
|
||||
// Instantiate an object of the given type. Return nil
|
||||
// if unknown.
|
||||
static SerialObj* Instantiate(SerialType type);
|
||||
|
||||
static const char* ClassName(SerialType type);
|
||||
|
||||
// Associate a "factory" function with the given type.
|
||||
// A factory is a class or function that creates instances
|
||||
// of a certain type.
|
||||
|
||||
typedef SerialObj* (*FactoryFunc)();
|
||||
static void Register(SerialType type, FactoryFunc f,
|
||||
const char* class_name);
|
||||
|
||||
static bool IsBroObj(SerialType type)
|
||||
{ return type & SER_IS_BRO_OBJ; }
|
||||
|
||||
static bool IsCacheStable(SerialType type)
|
||||
{ return type & SER_IS_CACHE_STABLE; }
|
||||
|
||||
static bool CheckTypes(SerialType type1, SerialType type2)
|
||||
{ return (type1 & SER_TYPE_MASK_PARENT) ==
|
||||
(type2 & SER_TYPE_MASK_PARENT); }
|
||||
|
||||
protected:
|
||||
friend class SerializationCache;
|
||||
|
||||
SerialObj()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
serial_type = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Serializes this object. If info->cache is false, we can use
|
||||
// DECLARE_NON_CACHEABLE_SERIAL (instead of DECLARE_SERIAL) which
|
||||
// avoids storing a per-object id.
|
||||
bool Serialize(SerialInfo* info) const;
|
||||
|
||||
// Unserializes next object.
|
||||
static SerialObj* Unserialize(UnserialInfo* info,
|
||||
SerialType type);
|
||||
|
||||
virtual bool DoSerialize(SerialInfo* info) const;
|
||||
virtual bool DoUnserialize(UnserialInfo* info);
|
||||
|
||||
typedef std::map<SerialType, FactoryFunc> FactoryMap;
|
||||
static FactoryMap* factories;
|
||||
|
||||
typedef std::map<SerialType, const char*> ClassNameMap;
|
||||
static ClassNameMap* names;
|
||||
|
||||
static uint64 time_counter;
|
||||
static uint64 IncreaseTimeCounter() { return ++time_counter; }
|
||||
static uint64 GetTimeCounter() { return time_counter; }
|
||||
|
||||
#ifdef DEBUG
|
||||
SerialType serial_type;
|
||||
#endif
|
||||
};
|
||||
|
||||
// A class that registers a factory function upon instantiation.
|
||||
class SerialTypeRegistrator {
|
||||
public:
|
||||
SerialTypeRegistrator(SerialType type, SerialObj::FactoryFunc func,
|
||||
const char* class_name)
|
||||
{
|
||||
SerialObj::Register(type, func, class_name);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Macro helpers.
|
||||
|
||||
#define DECLARE_ABSTRACT_SERIAL(classname) \
|
||||
virtual bool DoSerialize(SerialInfo*) const; \
|
||||
virtual bool DoUnserialize(UnserialInfo*); \
|
||||
|
||||
#define DECLARE_SERIAL(classname) \
|
||||
static classname* Instantiate(); \
|
||||
static SerialTypeRegistrator register_type; \
|
||||
virtual bool DoSerialize(SerialInfo*) const; \
|
||||
virtual bool DoUnserialize(UnserialInfo*); \
|
||||
virtual const TransientID* GetTID() const { return &tid; } \
|
||||
virtual SerialType GetSerialType() const; \
|
||||
TransientID tid;
|
||||
|
||||
// Only needed (and usable) for non-abstract classes.
|
||||
#define IMPLEMENT_SERIAL(classname, classtype) \
|
||||
SerialTypeRegistrator classname::register_type(classtype, \
|
||||
FactoryFunc(&classname::Instantiate), #classname); \
|
||||
SerialType classname::GetSerialType() const { return classtype; }; \
|
||||
classname* classname::Instantiate() { return new classname(); } \
|
||||
|
||||
// Pushes debug level on instantiation and pops when it goes out of scope.
|
||||
class AutoPush {
|
||||
public:
|
||||
AutoPush() { DBG_PUSH(DBG_SERIAL); }
|
||||
~AutoPush() { DBG_POP(DBG_SERIAL); }
|
||||
};
|
||||
|
||||
// Note that by default we disable suspending. Use DO_SERIALIZE_WITH_SUSPEND
|
||||
// to enable, but be careful to make sure that whomever calls us is aware of
|
||||
// the fact (or has already disabled suspension itself).
|
||||
#define DO_SERIALIZE(classtype, super) \
|
||||
DBG_LOG(DBG_SERIAL, __PRETTY_FUNCTION__); \
|
||||
if ( info->type == SER_NONE ) \
|
||||
info->type = classtype; \
|
||||
DisableSuspend suspend(info); \
|
||||
AutoPush auto_push; \
|
||||
if ( ! super::DoSerialize(info) ) \
|
||||
return false;
|
||||
|
||||
// Unfortunately, this is getting quite long. :-(
|
||||
#define DO_SERIALIZE_WITH_SUSPEND(classtype, super) \
|
||||
DBG_LOG(DBG_SERIAL, __PRETTY_FUNCTION__); \
|
||||
if ( info->type == SER_NONE ) \
|
||||
info->type = classtype; \
|
||||
AutoPush auto_push; \
|
||||
\
|
||||
bool call_super = info->cont.NewInstance(); \
|
||||
\
|
||||
if ( info->cont.ChildSuspended() ) \
|
||||
{ \
|
||||
void* user_ptr = info->cont.RestoreState(); \
|
||||
if ( user_ptr == &call_super ) \
|
||||
call_super = true; \
|
||||
} \
|
||||
\
|
||||
if ( call_super ) \
|
||||
{ \
|
||||
info->cont.SaveState(&call_super); \
|
||||
info->cont.SaveContext(); \
|
||||
bool result = super::DoSerialize(info); \
|
||||
info->cont.RestoreContext(); \
|
||||
if ( ! result ) \
|
||||
return false; \
|
||||
if ( info->cont.ChildSuspended() ) \
|
||||
return true; \
|
||||
info->cont.SaveState(0); \
|
||||
} \
|
||||
|
||||
#define DO_UNSERIALIZE(super) \
|
||||
DBG_LOG(DBG_SERIAL, __PRETTY_FUNCTION__); \
|
||||
AutoPush auto_push; \
|
||||
if ( ! super::DoUnserialize(info) ) \
|
||||
return false;
|
||||
|
||||
#define SERIALIZE(x) \
|
||||
info->s->Write(x, #x)
|
||||
|
||||
#define SERIALIZE_STR(x, y) \
|
||||
info->s->Write(x, y, #x)
|
||||
|
||||
#define SERIALIZE_BIT(bit) \
|
||||
info->s->Write(bool(bit), #bit)
|
||||
|
||||
#define UNSERIALIZE(x) \
|
||||
info->s->Read(x, #x)
|
||||
|
||||
#define UNSERIALIZE_STR(x, y) \
|
||||
info->s->Read(x, y, #x)
|
||||
|
||||
#define UNSERIALIZE_BIT(bit) \
|
||||
{ \
|
||||
bool tmp; \
|
||||
if ( ! info->s->Read(&tmp, #bit) ) \
|
||||
return false; \
|
||||
bit = (unsigned int) tmp; \
|
||||
}
|
||||
|
||||
// Some helpers for pointers which may be nil.
|
||||
#define SERIALIZE_OPTIONAL(ptr) \
|
||||
{ \
|
||||
if ( ptr ) \
|
||||
{ \
|
||||
if ( ! info->cont.ChildSuspended() ) \
|
||||
if ( ! info->s->Write(true, "has_" #ptr) ) \
|
||||
return false; \
|
||||
\
|
||||
info->cont.SaveContext(); \
|
||||
bool result = ptr->Serialize(info); \
|
||||
info->cont.RestoreContext(); \
|
||||
if ( ! result ) \
|
||||
return false; \
|
||||
\
|
||||
if ( info->cont.ChildSuspended() ) \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
else if ( ! info->s->Write(false, "has_" #ptr) ) \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define SERIALIZE_OPTIONAL_STR(str) \
|
||||
{ \
|
||||
if ( str ) \
|
||||
{ \
|
||||
if ( ! (info->s->Write(true, "has_" #str) && info->s->Write(str, "str")) ) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
else if ( ! info->s->Write(false, "has_" #str) ) \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define UNSERIALIZE_OPTIONAL(dst, unserialize) \
|
||||
{ \
|
||||
bool has_it; \
|
||||
if ( ! info->s->Read(&has_it, "has_" #dst) ) \
|
||||
return false; \
|
||||
\
|
||||
if ( has_it ) \
|
||||
{ \
|
||||
dst = unserialize; \
|
||||
if ( ! dst ) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
else \
|
||||
dst = 0; \
|
||||
}
|
||||
|
||||
#define UNSERIALIZE_OPTIONAL_STR(dst) \
|
||||
{ \
|
||||
bool has_it; \
|
||||
if ( ! info->s->Read(&has_it, "has_" #dst) ) \
|
||||
return false; \
|
||||
\
|
||||
if ( has_it ) \
|
||||
{ \
|
||||
info->s->Read(&dst, 0, "has_" #dst); \
|
||||
if ( ! dst ) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
else \
|
||||
dst = 0; \
|
||||
}
|
||||
|
||||
#define UNSERIALIZE_OPTIONAL_STATIC(dst, unserialize, del) \
|
||||
{ \
|
||||
bool has_it; \
|
||||
if ( ! info->s->Read(&has_it, "has_" #dst) ) \
|
||||
{ \
|
||||
delete del; \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
if ( has_it ) \
|
||||
{ \
|
||||
dst = unserialize; \
|
||||
if ( ! dst ) \
|
||||
{ \
|
||||
delete del; \
|
||||
return 0; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
else \
|
||||
dst = 0; \
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue