1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* ***** BEGIN LICENSE BLOCK ***** 3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 4 * 5 * The contents of this file are subject to the Mozilla Public License Version 6 * 1.1 (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * http://www.mozilla.org/MPL/ 9 * 10 * Software distributed under the License is distributed on an "AS IS" basis, 11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 12 * for the specific language governing rights and limitations under the 13 * License. 14 * 15 * The Original Code is mozilla.org code. 16 * 17 * The Initial Developer of the Original Code is 18 * Netscape Communications Corporation. 19 * Portions created by the Initial Developer are Copyright (C) 1999 20 * the Initial Developer. All Rights Reserved. 21 * 22 * Contributor(s): 23 * 24 * Alternatively, the contents of this file may be used under the terms of 25 * either of the GNU General Public License Version 2 or later (the "GPL"), 26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 27 * in which case the provisions of the GPL or the LGPL are applicable instead 28 * of those above. If you wish to allow use of your version of this file only 29 * under the terms of either the GPL or the LGPL, and not to allow others to 30 * use your version of this file under the terms of the MPL, indicate your 31 * decision by deleting the provisions above and replace them with the notice 32 * and other provisions required by the GPL or the LGPL. If you do not delete 33 * the provisions above, a recipient may use your version of this file under 34 * the terms of any one of the MPL, the GPL or the LGPL. 35 * 36 * ***** END LICENSE BLOCK ***** */ 37 38 #ifndef _MORKNODE_ 39 #define _MORKNODE_ 1 40 41 #ifndef _MORK_ 42 # include "mork.h" 43 #endif 44 45 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 46 47 #define morkUsage_kHeap 'h' 48 #define morkUsage_kStack 's' 49 #define morkUsage_kMember 'm' 50 #define morkUsage_kGlobal 'g' 51 #define morkUsage_kPool 'p' 52 #define morkUsage_kNone 'n' 53 54 class morkUsage { 55 public: 56 mork_usage mUsage_Code; // kHeap, kStack, kMember, or kGhost 57 58 public: 59 explicit morkUsage(mork_usage inCode); 60 61 morkUsage(); // does nothing except maybe call EnsureReadyStaticUsage() InitUsage(mork_usage inCode)62 void InitUsage(mork_usage inCode) { mUsage_Code = inCode; } 63 ~morkUsage()64 ~morkUsage() {} Code()65 mork_usage Code() const { return mUsage_Code; } 66 67 static void EnsureReadyStaticUsage(); 68 69 public: 70 static const morkUsage& kHeap; // morkUsage_kHeap 71 static const morkUsage& kStack; // morkUsage_kStack 72 static const morkUsage& kMember; // morkUsage_kMember 73 static const morkUsage& kGlobal; // morkUsage_kGlobal 74 static const morkUsage& kPool; // morkUsage_kPool 75 static const morkUsage& kNone; // morkUsage_kNone 76 77 static const morkUsage& GetHeap(); // kHeap, safe at static init time 78 static const morkUsage& GetStack(); // kStack, safe at static init time 79 static const morkUsage& GetMember(); // kMember, safe at static init time 80 static const morkUsage& GetGlobal(); // kGlobal, safe at static init time 81 static const morkUsage& GetPool(); // kPool, safe at static init time 82 static const morkUsage& GetNone(); // kNone, safe at static init time 83 }; 84 85 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 86 87 #define morkNode_kMaxRefCount 0x0FFFF /* count sticks if it hits this */ 88 89 #define morkBase_kNode /*i*/ 0x4E64 /* ascii 'Nd' */ 90 91 /*| morkNode: several groups of two-byte integers that track the basic 92 **| status of an object that can be used to compose in-memory graphs. 93 **| This is the base class for nsIMdbObject (which adds members that fit 94 **| the needs of an nsIMdbObject subclass). The morkNode class is also used 95 **| as the base class for other Mork db classes with no strong relation to 96 **| the MDB class hierarchy. 97 **| 98 **|| Heap: the heap in which this node was allocated, when the usage equals 99 **| morkUsage_kHeap to show dynamic allocation. Note this heap is NOT ref- 100 **| counted, because that would be too great and complex a burden for all 101 **| the nodes allocated in that heap. So heap users should take care to 102 **| understand that nodes allocated in that heap are considered protected 103 **| by some inclusive context in which all those nodes are allocated, and 104 **| that context must maintain at least one strong refcount for the heap. 105 **| Occasionally a node subclass will indeed wish to hold a refcounted 106 **| reference to a heap, and possibly the same heap that is in mNode_Heap, 107 **| but this is always done in a separate slot that explicitly refcounts, 108 **| so we avoid confusing what is meant by the mNode_Heap slot. 109 |*/ 110 class morkNode /*: public nsISupports */ { // base class for constructing Mork 111 // object graphs 112 113 public: // state is public because the entire Mork system is private 114 // NS_DECL_ISUPPORTS; 115 nsIMdbHeap* mNode_Heap; // NON-refcounted heap pointer 116 117 mork_base mNode_Base; // must equal morkBase_kNode 118 mork_derived mNode_Derived; // depends on specific node subclass 119 120 mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead 121 mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone 122 mork_able mNode_Mutable; // can this node be modified? 123 mork_load mNode_Load; // is this node clean or dirty? 124 125 mork_uses mNode_Uses; // refcount for strong refs 126 mork_refs mNode_Refs; // refcount for strong refs + weak refs 127 128 protected: // special case empty construction for morkHandleFrame 129 friend class morkHandleFrame; morkNode()130 morkNode() {} 131 132 public: // inlines for weird mNode_Mutable and mNode_Load constants SetFrozen()133 void SetFrozen() { mNode_Mutable = morkAble_kDisabled; } SetMutable()134 void SetMutable() { mNode_Mutable = morkAble_kEnabled; } SetAsleep()135 void SetAsleep() { mNode_Mutable = morkAble_kAsleep; } 136 IsFrozen()137 mork_bool IsFrozen() const { return mNode_Mutable == morkAble_kDisabled; } IsMutable()138 mork_bool IsMutable() const { return mNode_Mutable == morkAble_kEnabled; } IsAsleep()139 mork_bool IsAsleep() const { return mNode_Mutable == morkAble_kAsleep; } 140 SetNodeClean()141 void SetNodeClean() { mNode_Load = morkLoad_kClean; } SetNodeDirty()142 void SetNodeDirty() { mNode_Load = morkLoad_kDirty; } 143 IsNodeClean()144 mork_bool IsNodeClean() const { return mNode_Load == morkLoad_kClean; } IsNodeDirty()145 mork_bool IsNodeDirty() const { return mNode_Load == morkLoad_kDirty; } 146 147 public: // morkNode memory management methods 148 static void* MakeNew(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev); 149 150 void ZapOld(morkEnv* ev, nsIMdbHeap* ioHeap); // replaces operator delete() 151 // this->morkNode::~morkNode(); // first call polymorphic destructor 152 // if ( ioHeap ) // was this node heap allocated? 153 // ioHeap->Free(ev->AsMdbEnv(), this); 154 155 public: // morkNode memory management operators new(size_t inSize,nsIMdbHeap & ioHeap,morkEnv * ev)156 void* operator new(size_t inSize, nsIMdbHeap& ioHeap, 157 morkEnv* ev) noexcept(true) { 158 return morkNode::MakeNew(inSize, ioHeap, ev); 159 } 160 161 protected: // construction without an anv needed for first env constructed: 162 morkNode(const morkUsage& inUsage, nsIMdbHeap* ioHeap); 163 164 explicit morkNode(mork_usage inCode); // usage == inCode, heap == nil 165 166 // { ===== begin basic node interface ===== 167 public: // morkNode virtual methods 168 // virtual FlushMorkNode(morkEnv* ev, morkStream* ioStream); 169 // virtual WriteMorkNode(morkEnv* ev, morkStream* ioStream); 170 171 virtual ~morkNode(); // assert that CloseNode() executed earlier 172 virtual void CloseMorkNode(morkEnv* ev); // CloseNode() only if open 173 174 // CloseMorkNode() is the polymorphic close method called when uses==0, 175 // which must do NOTHING at all when IsOpenNode() is not true. Otherwise, 176 // CloseMorkNode() should call a static close method specific to an object. 177 // Each such static close method should either call inherited static close 178 // methods, or else perform the consolidated effect of calling them, where 179 // subclasses should closely track any changes in base classes with care. 180 181 public: // morkNode construction 182 morkNode(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap); 183 void CloseNode(morkEnv* ev); // called by CloseMorkNode(); 184 nsresult CloseMdbObject(morkEnv* ev); 185 NS_IMETHOD CloseMdbObject(nsIMdbEnv* ev); 186 187 private: // copying is not allowed 188 morkNode(const morkNode& other); 189 morkNode& operator=(const morkNode& other); 190 191 public: // dynamic type identification IsNode()192 mork_bool IsNode() const { return mNode_Base == morkBase_kNode; } 193 // } ===== end basic node methods ===== 194 195 public: // public error & warning methods 196 void RefsUnderUsesWarning( 197 morkEnv* ev) const; // call if mNode_Refs < mNode_Uses 198 void NonNodeError(morkEnv* ev) const; // call when IsNode() is false 199 void NilHeapError(morkEnv* ev) const; // zero mNode_Heap when usage is kHeap 200 void NonOpenNodeError(morkEnv* ev) const; // call when IsOpenNode() is false 201 202 void NonMutableNodeError(morkEnv* ev) const; // when IsMutable() is false 203 204 void RefsOverflowWarning(morkEnv* ev) const; // call on mNode_Refs overflow 205 void UsesOverflowWarning(morkEnv* ev) const; // call on mNode_Uses overflow 206 void RefsUnderflowWarning(morkEnv* ev) const; // call on mNode_Refs underflow 207 void UsesUnderflowWarning(morkEnv* ev) const; // call on mNode_Uses underflow 208 209 private: // private refcounting methods 210 mork_bool cut_use_count(morkEnv* ev); // just one part of CutStrongRef() 211 212 public: // other morkNode methods GoodRefs()213 mork_bool GoodRefs() const { return mNode_Refs >= mNode_Uses; } BadRefs()214 mork_bool BadRefs() const { return mNode_Refs < mNode_Uses; } 215 StrongRefsOnly()216 mork_uses StrongRefsOnly() const { return mNode_Uses; } WeakRefsOnly()217 mork_refs WeakRefsOnly() const { 218 return (mork_refs)(mNode_Refs - mNode_Uses); 219 } 220 221 // (this refcounting derives from public domain IronDoc node refcounts) 222 virtual mork_uses AddStrongRef(morkEnv* ev); 223 virtual mork_uses CutStrongRef(morkEnv* ev); 224 mork_refs AddWeakRef(morkEnv* ev); 225 mork_refs CutWeakRef(morkEnv* ev); 226 227 const char* GetNodeAccessAsString() const; // e.g. "open", "shut", etc. 228 const char* GetNodeUsageAsString() const; // e.g. "heap", "stack", etc. 229 NodeUsage()230 mork_usage NodeUsage() const { return mNode_Usage; } 231 IsHeapNode()232 mork_bool IsHeapNode() const { return mNode_Usage == morkUsage_kHeap; } 233 IsOpenNode()234 mork_bool IsOpenNode() const { return mNode_Access == morkAccess_kOpen; } 235 IsShutNode()236 mork_bool IsShutNode() const { return mNode_Access == morkAccess_kShut; } 237 IsDeadNode()238 mork_bool IsDeadNode() const { return mNode_Access == morkAccess_kDead; } 239 IsClosingNode()240 mork_bool IsClosingNode() const { 241 return mNode_Access == morkAccess_kClosing; 242 } 243 IsOpenOrClosingNode()244 mork_bool IsOpenOrClosingNode() const { 245 return IsOpenNode() || IsClosingNode(); 246 } 247 HasNodeAccess()248 mork_bool HasNodeAccess() const { 249 return (IsOpenNode() || IsShutNode() || IsClosingNode()); 250 } 251 MarkShut()252 void MarkShut() { mNode_Access = morkAccess_kShut; } MarkClosing()253 void MarkClosing() { mNode_Access = morkAccess_kClosing; } MarkDead()254 void MarkDead() { mNode_Access = morkAccess_kDead; } 255 256 public: // refcounting for typesafe subclass inline methods 257 static void SlotWeakNode(morkNode* me, morkEnv* ev, morkNode** ioSlot); 258 // If *ioSlot is non-nil, that node is released by CutWeakRef() and 259 // then zeroed out. Then if me is non-nil, this is acquired by 260 // calling AddWeakRef(), and if positive is returned to show success, 261 // then this is put into slot *ioSlot. Note me can be nil, so we 262 // permit expression '((morkNode*) 0L)->SlotWeakNode(ev, &slot)'. 263 264 static void SlotStrongNode(morkNode* me, morkEnv* ev, morkNode** ioSlot); 265 // If *ioSlot is non-nil, that node is released by CutStrongRef() and 266 // then zeroed out. Then if me is non-nil, this is acquired by 267 // calling AddStrongRef(), and if positive is returned to show success, 268 // then me is put into slot *ioSlot. Note me can be nil, so we take 269 // expression 'morkNode::SlotStrongNode((morkNode*) 0, ev, &slot)'. 270 }; 271 272 extern void // utility method very similar to morkNode::SlotStrongNode(): 273 nsIMdbHeap_SlotStrongHeap(nsIMdbHeap* self, morkEnv* ev, nsIMdbHeap** ioSlot); 274 // If *ioSlot is non-nil, that heap is released by CutStrongRef() and 275 // then zeroed out. Then if self is non-nil, this is acquired by 276 // calling AddStrongRef(), and if the return value shows success, 277 // then self is put into slot *ioSlot. Note self can be nil, so we take 278 // expression 'nsIMdbHeap_SlotStrongHeap(0, ev, &slot)'. 279 280 extern void // utility method very similar to morkNode::SlotStrongNode(): 281 nsIMdbFile_SlotStrongFile(nsIMdbFile* self, morkEnv* ev, nsIMdbFile** ioSlot); 282 // If *ioSlot is non-nil, that file is released by CutStrongRef() and 283 // then zeroed out. Then if self is non-nil, this is acquired by 284 // calling AddStrongRef(), and if the return value shows success, 285 // then self is put into slot *ioSlot. Note self can be nil, so we take 286 // expression 'nsIMdbFile_SlotStrongFile(0, ev, &slot)'. 287 288 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 289 290 #endif /* _MORKNODE_ */ 291