IPersistable.h
// IPersistable.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2006
@import "cxPersistStore.h"
@import "OID.h"
@import "Ceda/cxObject/Object.h"
@import "Ceda/cxObject/CSpace.h"
namespace ceda
{
struct PSpace;
///////////////////////////////////////////////////////////////////////////////////////////////////
// PersistObjState
@def bool CEDA_VALIDATE_MARK_AS_DIRTY = false
// System required state in every persistable object
$struct+ PersistObjState
{
PersistObjState() {}
// Redefine copy semantics to comply with creation of a new distinct object
// Don't copy the OID. Instead the copy has a null OID.
PersistObjState(const PersistObjState& rhs) {}
PersistObjState& operator=(const PersistObjState& rhs) { return *this; }
@if (CEDA_VALIDATE_MARK_AS_DIRTY)
{
uint32 m_crc = 0; // CRC of serialised state used to validate calls to MarkAsDirty()
}
OID m_oid; // Uniquely identifies the object within the PersistStore
};
///////////////////////////////////////////////////////////////////////////////////////////////////
// IPersistable
$interface+ IPersistable : IObject
{
void VisitPrefs(IPrefVisitor& v) const;
bool RepresentsSubTree() const;
void Serialise(Archive& ar) const;
void Deserialise(InputArchive& ar);
void OnCreate(bool local);
PersistObjState& GetPersistObjState() const;
};
$function+ inline OID GetOid(ptr<const IPersistable> po)
{
return po->GetPersistObjState().m_oid;
}
// todo: why is this in a public header? Seems too dangerous.
inline void SetOid(ptr<const IPersistable> po, OID oid) { po->GetPersistObjState().m_oid = oid; }
@if (CEDA_VALIDATE_MARK_AS_DIRTY)
{
inline uint32 GetCrc32(ptr<const IPersistable> po) { return po->GetPersistObjState().m_crc; }
inline void SetCrc32(ptr<const IPersistable> po, uint32 crc) { po->GetPersistObjState().m_crc = crc; }
}
// It is vital that the programmer call this for each persistable object that is modified
// as part of a transaction.
//
// Failure to call this function may result in changes not being written to disk.
// Note that this function doesn't allocate OIDs to objects reachable from po.
//
// It is not necessary to set the PSpace in thread local storage
$function+ void MarkPersistentAsDirtyWithoutTrace(ptr<const IPersistable> po);
// Declares that 'child' is reachable from 'parent', so 'child' should have an OID allocated and be
// added to the PSpace (if not already)
//
// It is not necessary to set the PSpace in thread local storage
$function+ void DeclareReachable(ptr<const IPersistable> parent, ptr<const IPersistable> child, bool trace = true);
// If po has an associated PSpace then this function requires it to have been locked.
// It is not necessary to set either the CSpace or PSpace in thread local storage.
$function+ void OnGarbageCollectPersistable(ptr<const IPersistable> po);
$function+ ptr<IPersistable> BindObjectGivenOid(OID oid);
$function+ ptr<IPersistable> BindObjectInMemoryGivenOid(OID oid);
$function+ ptr<IPersistable> TryBindObjectGivenOid(OID oid);
/*
Async bind to the IPersistable object for the given oid which must not be null.
*/
$function+ ptr<IPersistable> AsyncBindObjectInMemoryGivenOid(OID oid);
// Makes a deep copy of the given object which may or may not be persistent (i.e. have an OID)
// The copy is created synchronously and is assumed to fit entirely in memory
// returns null if any object was found which is not reflected or is has no reflected create
// function.
$function+ ptr<IPersistable> SynchronousDeepCopyPersistableObject( ptr<IPersistable> po );
// Called after inserting the given variable 'child' under 'parent' in order to ensure oids are
// allocated (for when the variable contain prefs to freshly allocated objects).
cxPersistStore_API void DeclareVariableReachable(const TypeOps& rt, ptr<const IPersistable> parent, const void* child);
$mixin PersistableMixin
{
public:
~PersistableMixin()
{
cxAssert( !IsDirty() );
}
// Implementation of IPersistable
PersistObjState& GetPersistObjState() const { return m_persistObjState; }
void OnGarbageCollect() const
{
OnGarbageCollectPersistable($this);
BaseClass::OnGarbageCollect();
}
bool IsDirty() const { return $this->GetIObjectSysState().GetFlag(DBP_PO_DIRTY); }
void OnCreate(bool local) {}
void VisitPrefs(IPrefVisitor& v) const {}
bool RepresentsSubTree() const { return true; }
// It is not necessary to set the PSpace in thread local storage
void MarkAsDirtyWithoutTrace() const
{
@if (CEDA_VALIDATE_MARK_AS_DIRTY)
{
if (m_persistObjState.m_oid)
{
$this->GetIObjectSysState().SetFlag(DBP_PO_MARKED_DIRTY_CRC);
}
}
if (!IsDirty())
{
MarkPersistentAsDirtyWithoutTrace($this);
}
}
PSpace* GetParentPSpace() const
{
if (CSpace* cs = BaseClass::GetParentCSpace())
{
return (PSpace*) GetPtrSlot(cs,PTR_SLOT_PSpace);
}
else
{
return nullptr;
}
}
protected:
mutable PersistObjState m_persistObjState;
};
// This overload is consistent with GetOid(ptr<const IPersistable> po) and allows for
// better performance where virtual calls are not required
template <typename Base>
inline OID GetOid(const PersistableMixin<Base>* p) { return p->GetPersistObjState().m_oid; }
} // namespace ceda