diff options
Diffstat (limited to 'comm/mailnews/db/mork/morkNode.h')
-rw-r--r-- | comm/mailnews/db/mork/morkNode.h | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/comm/mailnews/db/mork/morkNode.h b/comm/mailnews/db/mork/morkNode.h new file mode 100644 index 0000000000..6518487a30 --- /dev/null +++ b/comm/mailnews/db/mork/morkNode.h @@ -0,0 +1,290 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _MORKNODE_ +#define _MORKNODE_ 1 + +#ifndef _MORK_ +# include "mork.h" +#endif + +// 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 + +#define morkUsage_kHeap 'h' +#define morkUsage_kStack 's' +#define morkUsage_kMember 'm' +#define morkUsage_kGlobal 'g' +#define morkUsage_kPool 'p' +#define morkUsage_kNone 'n' + +class morkUsage { + public: + mork_usage mUsage_Code; // kHeap, kStack, kMember, or kGhost + + public: + explicit morkUsage(mork_usage inCode); + + morkUsage(); // does nothing except maybe call EnsureReadyStaticUsage() + void InitUsage(mork_usage inCode) { mUsage_Code = inCode; } + + ~morkUsage() {} + mork_usage Code() const { return mUsage_Code; } + + static void EnsureReadyStaticUsage(); + + public: + static const morkUsage& kHeap; // morkUsage_kHeap + static const morkUsage& kStack; // morkUsage_kStack + static const morkUsage& kMember; // morkUsage_kMember + static const morkUsage& kGlobal; // morkUsage_kGlobal + static const morkUsage& kPool; // morkUsage_kPool + static const morkUsage& kNone; // morkUsage_kNone + + static const morkUsage& GetHeap(); // kHeap, safe at static init time + static const morkUsage& GetStack(); // kStack, safe at static init time + static const morkUsage& GetMember(); // kMember, safe at static init time + static const morkUsage& GetGlobal(); // kGlobal, safe at static init time + static const morkUsage& GetPool(); // kPool, safe at static init time + static const morkUsage& GetNone(); // kNone, safe at static init time +}; + +// 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 + +#define morkNode_kMaxRefCount 0x0FFFF /* count sticks if it hits this */ + +#define morkBase_kNode /*i*/ 0x4E64 /* ascii 'Nd' */ + +/*| morkNode: several groups of two-byte integers that track the basic +**| status of an object that can be used to compose in-memory graphs. +**| This is the base class for nsIMdbObject (which adds members that fit +**| the needs of an nsIMdbObject subclass). The morkNode class is also used +**| as the base class for other Mork db classes with no strong relation to +**| the MDB class hierarchy. +**| +**|| Heap: the heap in which this node was allocated, when the usage equals +**| morkUsage_kHeap to show dynamic allocation. Note this heap is NOT ref- +**| counted, because that would be too great and complex a burden for all +**| the nodes allocated in that heap. So heap users should take care to +**| understand that nodes allocated in that heap are considered protected +**| by some inclusive context in which all those nodes are allocated, and +**| that context must maintain at least one strong refcount for the heap. +**| Occasionally a node subclass will indeed wish to hold a refcounted +**| reference to a heap, and possibly the same heap that is in mNode_Heap, +**| but this is always done in a separate slot that explicitly refcounts, +**| so we avoid confusing what is meant by the mNode_Heap slot. +|*/ +class morkNode /*: public nsISupports */ { // base class for constructing Mork + // object graphs + + public: // state is public because the entire Mork system is private + // NS_DECL_ISUPPORTS; + nsIMdbHeap* mNode_Heap; // NON-refcounted heap pointer + + mork_base mNode_Base; // must equal morkBase_kNode + mork_derived mNode_Derived; // depends on specific node subclass + + mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead + mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone + mork_able mNode_Mutable; // can this node be modified? + mork_load mNode_Load; // is this node clean or dirty? + + mork_uses mNode_Uses; // refcount for strong refs + mork_refs mNode_Refs; // refcount for strong refs + weak refs + + protected: // special case empty construction for morkHandleFrame + friend class morkHandleFrame; + morkNode() {} + + public: // inlines for weird mNode_Mutable and mNode_Load constants + void SetFrozen() { mNode_Mutable = morkAble_kDisabled; } + void SetMutable() { mNode_Mutable = morkAble_kEnabled; } + void SetAsleep() { mNode_Mutable = morkAble_kAsleep; } + + mork_bool IsFrozen() const { return mNode_Mutable == morkAble_kDisabled; } + mork_bool IsMutable() const { return mNode_Mutable == morkAble_kEnabled; } + mork_bool IsAsleep() const { return mNode_Mutable == morkAble_kAsleep; } + + void SetNodeClean() { mNode_Load = morkLoad_kClean; } + void SetNodeDirty() { mNode_Load = morkLoad_kDirty; } + + mork_bool IsNodeClean() const { return mNode_Load == morkLoad_kClean; } + mork_bool IsNodeDirty() const { return mNode_Load == morkLoad_kDirty; } + + public: // morkNode memory management methods + static void* MakeNew(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev); + + void ZapOld(morkEnv* ev, nsIMdbHeap* ioHeap); // replaces operator delete() + // this->morkNode::~morkNode(); // first call polymorphic destructor + // if ( ioHeap ) // was this node heap allocated? + // ioHeap->Free(ev->AsMdbEnv(), this); + + public: // morkNode memory management operators + void* operator new(size_t inSize, nsIMdbHeap& ioHeap, + morkEnv* ev) noexcept(true) { + return morkNode::MakeNew(inSize, ioHeap, ev); + } + + protected: // construction without an anv needed for first env constructed: + morkNode(const morkUsage& inUsage, nsIMdbHeap* ioHeap); + + explicit morkNode(mork_usage inCode); // usage == inCode, heap == nil + + // { ===== begin basic node interface ===== + public: // morkNode virtual methods + // virtual FlushMorkNode(morkEnv* ev, morkStream* ioStream); + // virtual WriteMorkNode(morkEnv* ev, morkStream* ioStream); + + virtual ~morkNode(); // assert that CloseNode() executed earlier + virtual void CloseMorkNode(morkEnv* ev); // CloseNode() only if open + + // CloseMorkNode() is the polymorphic close method called when uses==0, + // which must do NOTHING at all when IsOpenNode() is not true. Otherwise, + // CloseMorkNode() should call a static close method specific to an object. + // Each such static close method should either call inherited static close + // methods, or else perform the consolidated effect of calling them, where + // subclasses should closely track any changes in base classes with care. + + public: // morkNode construction + morkNode(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap); + void CloseNode(morkEnv* ev); // called by CloseMorkNode(); + nsresult CloseMdbObject(morkEnv* ev); + NS_IMETHOD CloseMdbObject(nsIMdbEnv* ev); + + private: // copying is not allowed + morkNode(const morkNode& other); + morkNode& operator=(const morkNode& other); + + public: // dynamic type identification + mork_bool IsNode() const { return mNode_Base == morkBase_kNode; } + // } ===== end basic node methods ===== + + public: // public error & warning methods + void RefsUnderUsesWarning( + morkEnv* ev) const; // call if mNode_Refs < mNode_Uses + void NonNodeError(morkEnv* ev) const; // call when IsNode() is false + void NilHeapError(morkEnv* ev) const; // zero mNode_Heap when usage is kHeap + void NonOpenNodeError(morkEnv* ev) const; // call when IsOpenNode() is false + + void NonMutableNodeError(morkEnv* ev) const; // when IsMutable() is false + + void RefsOverflowWarning(morkEnv* ev) const; // call on mNode_Refs overflow + void UsesOverflowWarning(morkEnv* ev) const; // call on mNode_Uses overflow + void RefsUnderflowWarning(morkEnv* ev) const; // call on mNode_Refs underflow + void UsesUnderflowWarning(morkEnv* ev) const; // call on mNode_Uses underflow + + private: // private refcounting methods + mork_bool cut_use_count(morkEnv* ev); // just one part of CutStrongRef() + + public: // other morkNode methods + mork_bool GoodRefs() const { return mNode_Refs >= mNode_Uses; } + mork_bool BadRefs() const { return mNode_Refs < mNode_Uses; } + + mork_uses StrongRefsOnly() const { return mNode_Uses; } + mork_refs WeakRefsOnly() const { + return (mork_refs)(mNode_Refs - mNode_Uses); + } + + // (this refcounting derives from public domain IronDoc node refcounts) + virtual mork_uses AddStrongRef(morkEnv* ev); + virtual mork_uses CutStrongRef(morkEnv* ev); + mork_refs AddWeakRef(morkEnv* ev); + mork_refs CutWeakRef(morkEnv* ev); + + const char* GetNodeAccessAsString() const; // e.g. "open", "shut", etc. + const char* GetNodeUsageAsString() const; // e.g. "heap", "stack", etc. + + mork_usage NodeUsage() const { return mNode_Usage; } + + mork_bool IsHeapNode() const { return mNode_Usage == morkUsage_kHeap; } + + mork_bool IsOpenNode() const { return mNode_Access == morkAccess_kOpen; } + + mork_bool IsShutNode() const { return mNode_Access == morkAccess_kShut; } + + mork_bool IsDeadNode() const { return mNode_Access == morkAccess_kDead; } + + mork_bool IsClosingNode() const { + return mNode_Access == morkAccess_kClosing; + } + + mork_bool IsOpenOrClosingNode() const { + return IsOpenNode() || IsClosingNode(); + } + + mork_bool HasNodeAccess() const { + return (IsOpenNode() || IsShutNode() || IsClosingNode()); + } + + void MarkShut() { mNode_Access = morkAccess_kShut; } + void MarkClosing() { mNode_Access = morkAccess_kClosing; } + void MarkDead() { mNode_Access = morkAccess_kDead; } + + public: // refcounting for typesafe subclass inline methods + static void SlotWeakNode(morkNode* me, morkEnv* ev, morkNode** ioSlot); + // If *ioSlot is non-nil, that node is released by CutWeakRef() and + // then zeroed out. Then if me is non-nil, this is acquired by + // calling AddWeakRef(), and if positive is returned to show success, + // then this is put into slot *ioSlot. Note me can be nil, so we + // permit expression '((morkNode*) 0L)->SlotWeakNode(ev, &slot)'. + + static void SlotStrongNode(morkNode* me, morkEnv* ev, morkNode** ioSlot); + // If *ioSlot is non-nil, that node is released by CutStrongRef() and + // then zeroed out. Then if me is non-nil, this is acquired by + // calling AddStrongRef(), and if positive is returned to show success, + // then me is put into slot *ioSlot. Note me can be nil, so we take + // expression 'morkNode::SlotStrongNode((morkNode*) 0, ev, &slot)'. +}; + +extern void // utility method very similar to morkNode::SlotStrongNode(): +nsIMdbHeap_SlotStrongHeap(nsIMdbHeap* self, morkEnv* ev, nsIMdbHeap** ioSlot); +// If *ioSlot is non-nil, that heap is released by CutStrongRef() and +// then zeroed out. Then if self is non-nil, this is acquired by +// calling AddStrongRef(), and if the return value shows success, +// then self is put into slot *ioSlot. Note self can be nil, so we take +// expression 'nsIMdbHeap_SlotStrongHeap(0, ev, &slot)'. + +extern void // utility method very similar to morkNode::SlotStrongNode(): +nsIMdbFile_SlotStrongFile(nsIMdbFile* self, morkEnv* ev, nsIMdbFile** ioSlot); +// If *ioSlot is non-nil, that file is released by CutStrongRef() and +// then zeroed out. Then if self is non-nil, this is acquired by +// calling AddStrongRef(), and if the return value shows success, +// then self is put into slot *ioSlot. Note self can be nil, so we take +// expression 'nsIMdbFile_SlotStrongFile(0, ev, &slot)'. + +// 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 + +#endif /* _MORKNODE_ */ |