Back to index

lightning-sunbird  0.9+nobinonly
morkNode.h
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-  */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #ifndef _MORKNODE_
00039 #define _MORKNODE_ 1
00040 
00041 #ifndef _MORK_
00042 #include "mork.h"
00043 #endif
00044 
00045 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00046 
00047 #define morkUsage_kHeap    'h'
00048 #define morkUsage_kStack   's'
00049 #define morkUsage_kMember  'm'
00050 #define morkUsage_kGlobal  'g'
00051 #define morkUsage_kPool    'p'
00052 #define morkUsage_kNone    'n'
00053 
00054 class morkUsage {
00055 public:
00056   mork_usage     mUsage_Code;  // kHeap, kStack, kMember, or kGhost
00057   
00058 public:
00059   morkUsage(mork_usage inCode);
00060 
00061   morkUsage(); // does nothing except maybe call EnsureReadyStaticUsage()
00062   void InitUsage( mork_usage inCode)
00063   { mUsage_Code = inCode; }
00064   
00065   ~morkUsage() { }
00066   mork_usage Code() const { return mUsage_Code; }
00067   
00068   static void EnsureReadyStaticUsage();
00069   
00070 public:
00071   static const morkUsage& kHeap;      // morkUsage_kHeap
00072   static const morkUsage& kStack;     // morkUsage_kStack
00073   static const morkUsage& kMember;    // morkUsage_kMember
00074   static const morkUsage& kGlobal;    // morkUsage_kGlobal
00075   static const morkUsage& kPool;      // morkUsage_kPool
00076   static const morkUsage& kNone;      // morkUsage_kNone
00077   
00078   static const morkUsage& GetHeap();   // kHeap, safe at static init time
00079   static const morkUsage& GetStack();  // kStack, safe at static init time
00080   static const morkUsage& GetMember(); // kMember, safe at static init time
00081   static const morkUsage& GetGlobal(); // kGlobal, safe at static init time
00082   static const morkUsage& GetPool();   // kPool, safe at static init time
00083   static const morkUsage& GetNone();   // kNone, safe at static init time
00084     
00085 };
00086 
00087 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00088 
00089 #define morkNode_kMaxRefCount 0x0FFFF /* count sticks if it hits this */
00090 
00091 #define morkBase_kNode      /*i*/ 0x4E64 /* ascii 'Nd' */
00092 
00093 /*| morkNode: several groups of two-byte integers that track the basic
00094 **| status of an object that can be used to compose in-memory graphs.
00095 **| This is the base class for nsIMdbObject (which adds members that fit
00096 **| the needs of an nsIMdbObject subclass).  The morkNode class is also used
00097 **| as the base class for other Mork db classes with no strong relation to
00098 **| the MDB class hierarchy.
00099 **|
00100 **|| Heap: the heap in which this node was allocated, when the usage equals
00101 **| morkUsage_kHeap to show dynamic allocation.  Note this heap is NOT ref-
00102 **| counted, because that would be too great and complex a burden for all
00103 **| the nodes allocated in that heap.  So heap users should take care to
00104 **| understand that nodes allocated in that heap are considered protected
00105 **| by some inclusive context in which all those nodes are allocated, and
00106 **| that context must maintain at least one strong refcount for the heap.
00107 **| Occasionally a node subclass will indeed wish to hold a refcounted
00108 **| reference to a heap, and possibly the same heap that is in mNode_Heap,
00109 **| but this is always done in a separate slot that explicitly refcounts,
00110 **| so we avoid confusing what is meant by the mNode_Heap slot.
00111 |*/
00112 class morkNode /*: public nsISupports */ { // base class for constructing Mork object graphs
00113 
00114 public: // state is public because the entire Mork system is private
00115   
00116 //  NS_DECL_ISUPPORTS;
00117   nsIMdbHeap*    mNode_Heap;     // NON-refcounted heap pointer
00118 
00119   mork_base      mNode_Base;     // must equal morkBase_kNode
00120   mork_derived   mNode_Derived;  // depends on specific node subclass
00121   
00122   mork_access    mNode_Access;   // kOpen, kClosing, kShut, or kDead
00123   mork_usage     mNode_Usage;    // kHeap, kStack, kMember, kGlobal, kNone
00124   mork_able      mNode_Mutable;  // can this node be modified?
00125   mork_load      mNode_Load;     // is this node clean or dirty?
00126   
00127   mork_uses      mNode_Uses;     // refcount for strong refs
00128   mork_refs      mNode_Refs;     // refcount for strong refs + weak refs
00129   
00130 protected: // special case empty construction for morkHandleFrame
00131   friend class morkHandleFrame;
00132   morkNode() { }
00133   
00134 public: // inlines for weird mNode_Mutable and mNode_Load constants
00135 
00136   void SetFrozen() { mNode_Mutable = morkAble_kDisabled; }
00137   void SetMutable() { mNode_Mutable = morkAble_kEnabled; }
00138   void SetAsleep() { mNode_Mutable = morkAble_kAsleep; }
00139   
00140   mork_bool IsFrozen() const { return mNode_Mutable == morkAble_kDisabled; }
00141   mork_bool IsMutable() const { return mNode_Mutable == morkAble_kEnabled; }
00142   mork_bool IsAsleep() const { return mNode_Mutable == morkAble_kAsleep; }
00143 
00144   void SetNodeClean() { mNode_Load = morkLoad_kClean; }
00145   void SetNodeDirty() { mNode_Load = morkLoad_kDirty; }
00146   
00147   mork_bool IsNodeClean() const { return mNode_Load == morkLoad_kClean; }
00148   mork_bool IsNodeDirty() const { return mNode_Load == morkLoad_kDirty; }
00149   
00150 public: // morkNode memory management methods
00151   static void* MakeNew(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev);
00152   
00153   void ZapOld(morkEnv* ev, nsIMdbHeap* ioHeap); // replaces operator delete()
00154   // this->morkNode::~morkNode(); // first call polymorphic destructor
00155   // if ( ioHeap ) // was this node heap allocated?
00156   //    ioHeap->Free(ev->AsMdbEnv(), this);
00157 
00158 public: // morkNode memory management operators
00159   void* operator new(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev) CPP_THROW_NEW
00160   { return morkNode::MakeNew(inSize, ioHeap, ev); }
00161   
00162 
00163 protected: // construction without an anv needed for first env constructed:
00164   morkNode(const morkUsage& inUsage, nsIMdbHeap* ioHeap);
00165 
00166   morkNode(mork_usage inCode); // usage == inCode, heap == nil
00167 
00168 // { ===== begin basic node interface =====
00169 public: // morkNode virtual methods
00170   // virtual FlushMorkNode(morkEnv* ev, morkStream* ioStream);
00171   // virtual WriteMorkNode(morkEnv* ev, morkStream* ioStream);
00172   
00173   virtual ~morkNode(); // assert that CloseNode() executed earlier
00174   virtual void CloseMorkNode(morkEnv* ev); // CloseNode() only if open
00175   
00176   // CloseMorkNode() is the polymorphic close method called when uses==0,
00177   // which must do NOTHING at all when IsOpenNode() is not true.  Otherwise,
00178   // CloseMorkNode() should call a static close method specific to an object.
00179   // Each such static close method should either call inherited static close
00180   // methods, or else perform the consolidated effect of calling them, where
00181   // subclasses should closely track any changes in base classes with care.
00182   
00183 public: // morkNode construction
00184   morkNode(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap);
00185   void CloseNode(morkEnv* ev); // called by CloseMorkNode();
00186   mdb_err CloseMdbObject(morkEnv *ev);
00187   NS_IMETHOD CloseMdbObject(nsIMdbEnv *ev);
00188 private: // copying is not allowed
00189   morkNode(const morkNode& other);
00190   morkNode& operator=(const morkNode& other);
00191 
00192 public: // dynamic type identification
00193   mork_bool IsNode() const
00194   { return mNode_Base == morkBase_kNode; }
00195 // } ===== end basic node methods =====
00196     
00197 public: // public error & warning methods
00198 
00199   void RefsUnderUsesWarning(morkEnv* ev) const; // call if mNode_Refs < mNode_Uses
00200   void NonNodeError(morkEnv* ev) const; // call when IsNode() is false
00201   void NilHeapError(morkEnv* ev) const; // zero mNode_Heap when usage is kHeap
00202   void NonOpenNodeError(morkEnv* ev) const; // call when IsOpenNode() is false
00203 
00204   void NonMutableNodeError(morkEnv* ev) const; // when IsMutable() is false
00205 
00206   void RefsOverflowWarning(morkEnv* ev) const; // call on mNode_Refs overflow
00207   void UsesOverflowWarning(morkEnv* ev) const; // call on mNode_Uses overflow
00208   void RefsUnderflowWarning(morkEnv* ev) const; // call on mNode_Refs underflow
00209   void UsesUnderflowWarning(morkEnv* ev) const; // call on mNode_Uses underflow
00210 
00211 private: // private refcounting methods
00212   mork_bool  cut_use_count(morkEnv* ev); // just one part of CutStrongRef()
00213 
00214 public: // other morkNode methods
00215 
00216   mork_bool  GoodRefs() const { return mNode_Refs >= mNode_Uses; }
00217   mork_bool  BadRefs() const { return mNode_Refs < mNode_Uses; }
00218 
00219   mork_uses  StrongRefsOnly() const { return mNode_Uses; }
00220   mork_refs  WeakRefsOnly() const { return (mork_refs) ( mNode_Refs - mNode_Uses ); }
00221 
00222   // (this refcounting derives from public domain IronDoc node refcounts)
00223   virtual mork_refs    AddStrongRef(morkEnv* ev);
00224   virtual mork_refs    CutStrongRef(morkEnv* ev);
00225   mork_refs    AddWeakRef(morkEnv* ev);
00226   mork_refs    CutWeakRef(morkEnv* ev);
00227 
00228   const char* GetNodeAccessAsString() const; // e.g. "open", "shut", etc.
00229   const char* GetNodeUsageAsString() const; // e.g. "heap", "stack", etc.
00230 
00231   mork_usage NodeUsage() const { return mNode_Usage; }
00232 
00233   mork_bool IsHeapNode() const
00234   { return mNode_Usage == morkUsage_kHeap; }
00235 
00236   mork_bool IsOpenNode() const
00237   { return mNode_Access == morkAccess_kOpen; }
00238 
00239   mork_bool IsShutNode() const
00240   { return mNode_Access == morkAccess_kShut; }
00241 
00242   mork_bool IsDeadNode() const
00243   { return mNode_Access == morkAccess_kDead; }
00244 
00245   mork_bool IsClosingNode() const
00246   { return mNode_Access == morkAccess_kClosing; }
00247 
00248   mork_bool IsOpenOrClosingNode() const
00249   { return IsOpenNode() || IsClosingNode(); }
00250 
00251   mork_bool HasNodeAccess() const
00252   { return ( IsOpenNode() || IsShutNode() || IsClosingNode() ); }
00253     
00254   void MarkShut() { mNode_Access = morkAccess_kShut; }
00255   void MarkClosing() { mNode_Access = morkAccess_kClosing; }
00256   void MarkDead() { mNode_Access = morkAccess_kDead; }
00257 
00258 public: // refcounting for typesafe subclass inline methods
00259   static void SlotWeakNode(morkNode* me, morkEnv* ev, morkNode** ioSlot);
00260   // If *ioSlot is non-nil, that node is released by CutWeakRef() and
00261   // then zeroed out.  Then if me is non-nil, this is acquired by
00262   // calling AddWeakRef(), and if positive is returned to show success,
00263   // then this is put into slot *ioSlot.  Note me can be nil, so we
00264   // permit expression '((morkNode*) 0L)->SlotWeakNode(ev, &slot)'.
00265   
00266   static void SlotStrongNode(morkNode* me, morkEnv* ev, morkNode** ioSlot);
00267   // If *ioSlot is non-nil, that node is released by CutStrongRef() and
00268   // then zeroed out.  Then if me is non-nil, this is acquired by
00269   // calling AddStrongRef(), and if positive is returned to show success,
00270   // then me is put into slot *ioSlot.  Note me can be nil, so we take
00271   // expression 'morkNode::SlotStrongNode((morkNode*) 0, ev, &slot)'.
00272 };
00273 
00274 extern void // utility method very similar to morkNode::SlotStrongNode():
00275 nsIMdbHeap_SlotStrongHeap(nsIMdbHeap* self, morkEnv* ev, nsIMdbHeap** ioSlot);
00276   // If *ioSlot is non-nil, that heap is released by CutStrongRef() and
00277   // then zeroed out.  Then if self is non-nil, this is acquired by
00278   // calling AddStrongRef(), and if the return value shows success,
00279   // then self is put into slot *ioSlot.  Note self can be nil, so we take
00280   // expression 'nsIMdbHeap_SlotStrongHeap(0, ev, &slot)'.
00281 
00282 extern void // utility method very similar to morkNode::SlotStrongNode():
00283 nsIMdbFile_SlotStrongFile(nsIMdbFile* self, morkEnv* ev, nsIMdbFile** ioSlot);
00284   // If *ioSlot is non-nil, that file is released by CutStrongRef() and
00285   // then zeroed out.  Then if self is non-nil, this is acquired by
00286   // calling AddStrongRef(), and if the return value shows success,
00287   // then self is put into slot *ioSlot.  Note self can be nil, so we take
00288   // expression 'nsIMdbFile_SlotStrongFile(0, ev, &slot)'.
00289 
00290 extern void // utility method very similar to morkNode::SlotStrongNode():
00291 nsIMdbCompare_SlotStrongCompare(nsIMdbCompare* self, morkEnv* ev,
00292   nsIMdbCompare** ioSlot);
00293   // If *ioSlot is non-nil, that compare is released by CutStrongRef() and
00294   // then zeroed out.  Then if self is non-nil, this is acquired by
00295   // calling AddStrongRef(), and if the return value shows success,
00296   // then self is put into slot *ioSlot.  Note self can be nil, so we take
00297   // expression 'nsIMdbCompare_SlotStrongCompare(0, ev, &slot)'.
00298 
00299 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00300 
00301 #endif /* _MORKNODE_ */