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
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/
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
15 * The Original Code is mozilla.org code.
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.
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.
36 * ***** END LICENSE BLOCK ***** */
45 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
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'
56 mork_usage mUsage_Code
; // kHeap, kStack, kMember, or kGhost
59 morkUsage(mork_usage inCode
);
61 morkUsage(); // does nothing except maybe call EnsureReadyStaticUsage()
62 void InitUsage( mork_usage inCode
)
63 { mUsage_Code
= inCode
; }
66 mork_usage
Code() const { return mUsage_Code
; }
68 static void EnsureReadyStaticUsage();
71 static const morkUsage
& kHeap
; // morkUsage_kHeap
72 static const morkUsage
& kStack
; // morkUsage_kStack
73 static const morkUsage
& kMember
; // morkUsage_kMember
74 static const morkUsage
& kGlobal
; // morkUsage_kGlobal
75 static const morkUsage
& kPool
; // morkUsage_kPool
76 static const morkUsage
& kNone
; // morkUsage_kNone
78 static const morkUsage
& GetHeap(); // kHeap, safe at static init time
79 static const morkUsage
& GetStack(); // kStack, safe at static init time
80 static const morkUsage
& GetMember(); // kMember, safe at static init time
81 static const morkUsage
& GetGlobal(); // kGlobal, safe at static init time
82 static const morkUsage
& GetPool(); // kPool, safe at static init time
83 static const morkUsage
& GetNone(); // kNone, safe at static init time
87 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
89 #define morkNode_kMaxRefCount 0x0FFFF /* count sticks if it hits this */
91 #define morkBase_kNode /*i*/ 0x4E64 /* ascii 'Nd' */
93 /*| morkNode: several groups of two-byte integers that track the basic
94 **| status of an object that can be used to compose in-memory graphs.
95 **| This is the base class for nsIMdbObject (which adds members that fit
96 **| the needs of an nsIMdbObject subclass). The morkNode class is also used
97 **| as the base class for other Mork db classes with no strong relation to
98 **| the MDB class hierarchy.
100 **|| Heap: the heap in which this node was allocated, when the usage equals
101 **| morkUsage_kHeap to show dynamic allocation. Note this heap is NOT ref-
102 **| counted, because that would be too great and complex a burden for all
103 **| the nodes allocated in that heap. So heap users should take care to
104 **| understand that nodes allocated in that heap are considered protected
105 **| by some inclusive context in which all those nodes are allocated, and
106 **| that context must maintain at least one strong refcount for the heap.
107 **| Occasionally a node subclass will indeed wish to hold a refcounted
108 **| reference to a heap, and possibly the same heap that is in mNode_Heap,
109 **| but this is always done in a separate slot that explicitly refcounts,
110 **| so we avoid confusing what is meant by the mNode_Heap slot.
112 class morkNode
/*: public nsISupports */ { // base class for constructing Mork object graphs
114 public: // state is public because the entire Mork system is private
116 // NS_DECL_ISUPPORTS;
117 nsIMdbHeap
* mNode_Heap
; // NON-refcounted heap pointer
119 mork_base mNode_Base
; // must equal morkBase_kNode
120 mork_derived mNode_Derived
; // depends on specific node subclass
122 mork_access mNode_Access
; // kOpen, kClosing, kShut, or kDead
123 mork_usage mNode_Usage
; // kHeap, kStack, kMember, kGlobal, kNone
124 mork_able mNode_Mutable
; // can this node be modified?
125 mork_load mNode_Load
; // is this node clean or dirty?
127 mork_uses mNode_Uses
; // refcount for strong refs
128 mork_refs mNode_Refs
; // refcount for strong refs + weak refs
130 protected: // special case empty construction for morkHandleFrame
131 friend class morkHandleFrame
;
134 public: // inlines for weird mNode_Mutable and mNode_Load constants
136 void SetFrozen() { mNode_Mutable
= morkAble_kDisabled
; }
137 void SetMutable() { mNode_Mutable
= morkAble_kEnabled
; }
138 void SetAsleep() { mNode_Mutable
= morkAble_kAsleep
; }
140 mork_bool
IsFrozen() const { return mNode_Mutable
== morkAble_kDisabled
; }
141 mork_bool
IsMutable() const { return mNode_Mutable
== morkAble_kEnabled
; }
142 mork_bool
IsAsleep() const { return mNode_Mutable
== morkAble_kAsleep
; }
144 void SetNodeClean() { mNode_Load
= morkLoad_kClean
; }
145 void SetNodeDirty() { mNode_Load
= morkLoad_kDirty
; }
147 mork_bool
IsNodeClean() const { return mNode_Load
== morkLoad_kClean
; }
148 mork_bool
IsNodeDirty() const { return mNode_Load
== morkLoad_kDirty
; }
150 public: // morkNode memory management methods
151 static void* MakeNew(size_t inSize
, nsIMdbHeap
& ioHeap
, morkEnv
* ev
);
153 void ZapOld(morkEnv
* ev
, nsIMdbHeap
* ioHeap
); // replaces operator delete()
154 // this->morkNode::~morkNode(); // first call polymorphic destructor
155 // if ( ioHeap ) // was this node heap allocated?
156 // ioHeap->Free(ev->AsMdbEnv(), this);
158 public: // morkNode memory management operators
159 void* operator new(size_t inSize
, nsIMdbHeap
& ioHeap
, morkEnv
* ev
) CPP_THROW_NEW
160 { return morkNode::MakeNew(inSize
, ioHeap
, ev
); }
163 protected: // construction without an anv needed for first env constructed:
164 morkNode(const morkUsage
& inUsage
, nsIMdbHeap
* ioHeap
);
166 morkNode(mork_usage inCode
); // usage == inCode, heap == nil
168 // { ===== begin basic node interface =====
169 public: // morkNode virtual methods
170 // virtual FlushMorkNode(morkEnv* ev, morkStream* ioStream);
171 // virtual WriteMorkNode(morkEnv* ev, morkStream* ioStream);
173 virtual ~morkNode(); // assert that CloseNode() executed earlier
174 virtual void CloseMorkNode(morkEnv
* ev
); // CloseNode() only if open
176 // CloseMorkNode() is the polymorphic close method called when uses==0,
177 // which must do NOTHING at all when IsOpenNode() is not true. Otherwise,
178 // CloseMorkNode() should call a static close method specific to an object.
179 // Each such static close method should either call inherited static close
180 // methods, or else perform the consolidated effect of calling them, where
181 // subclasses should closely track any changes in base classes with care.
183 public: // morkNode construction
184 morkNode(morkEnv
* ev
, const morkUsage
& inUsage
, nsIMdbHeap
* ioHeap
);
185 void CloseNode(morkEnv
* ev
); // called by CloseMorkNode();
186 mdb_err
CloseMdbObject(morkEnv
*ev
);
187 NS_IMETHOD
CloseMdbObject(nsIMdbEnv
*ev
);
188 private: // copying is not allowed
189 morkNode(const morkNode
& other
);
190 morkNode
& operator=(const morkNode
& other
);
192 public: // dynamic type identification
193 mork_bool
IsNode() const
194 { return mNode_Base
== morkBase_kNode
; }
195 // } ===== end basic node methods =====
197 public: // public error & warning methods
199 void RefsUnderUsesWarning(morkEnv
* ev
) const; // call if mNode_Refs < mNode_Uses
200 void NonNodeError(morkEnv
* ev
) const; // call when IsNode() is false
201 void NilHeapError(morkEnv
* ev
) const; // zero mNode_Heap when usage is kHeap
202 void NonOpenNodeError(morkEnv
* ev
) const; // call when IsOpenNode() is false
204 void NonMutableNodeError(morkEnv
* ev
) const; // when IsMutable() is false
206 void RefsOverflowWarning(morkEnv
* ev
) const; // call on mNode_Refs overflow
207 void UsesOverflowWarning(morkEnv
* ev
) const; // call on mNode_Uses overflow
208 void RefsUnderflowWarning(morkEnv
* ev
) const; // call on mNode_Refs underflow
209 void UsesUnderflowWarning(morkEnv
* ev
) const; // call on mNode_Uses underflow
211 private: // private refcounting methods
212 mork_bool
cut_use_count(morkEnv
* ev
); // just one part of CutStrongRef()
214 public: // other morkNode methods
216 mork_bool
GoodRefs() const { return mNode_Refs
>= mNode_Uses
; }
217 mork_bool
BadRefs() const { return mNode_Refs
< mNode_Uses
; }
219 mork_uses
StrongRefsOnly() const { return mNode_Uses
; }
220 mork_refs
WeakRefsOnly() const { return (mork_refs
) ( mNode_Refs
- mNode_Uses
); }
222 // (this refcounting derives from public domain IronDoc node refcounts)
223 virtual mork_refs
AddStrongRef(morkEnv
* ev
);
224 virtual mork_refs
CutStrongRef(morkEnv
* ev
);
225 mork_refs
AddWeakRef(morkEnv
* ev
);
226 mork_refs
CutWeakRef(morkEnv
* ev
);
228 const char* GetNodeAccessAsString() const; // e.g. "open", "shut", etc.
229 const char* GetNodeUsageAsString() const; // e.g. "heap", "stack", etc.
231 mork_usage
NodeUsage() const { return mNode_Usage
; }
233 mork_bool
IsHeapNode() const
234 { return mNode_Usage
== morkUsage_kHeap
; }
236 mork_bool
IsOpenNode() const
237 { return mNode_Access
== morkAccess_kOpen
; }
239 mork_bool
IsShutNode() const
240 { return mNode_Access
== morkAccess_kShut
; }
242 mork_bool
IsDeadNode() const
243 { return mNode_Access
== morkAccess_kDead
; }
245 mork_bool
IsClosingNode() const
246 { return mNode_Access
== morkAccess_kClosing
; }
248 mork_bool
IsOpenOrClosingNode() const
249 { return IsOpenNode() || IsClosingNode(); }
251 mork_bool
HasNodeAccess() const
252 { return ( IsOpenNode() || IsShutNode() || IsClosingNode() ); }
254 void MarkShut() { mNode_Access
= morkAccess_kShut
; }
255 void MarkClosing() { mNode_Access
= morkAccess_kClosing
; }
256 void MarkDead() { mNode_Access
= morkAccess_kDead
; }
258 public: // refcounting for typesafe subclass inline methods
259 static void SlotWeakNode(morkNode
* me
, morkEnv
* ev
, morkNode
** ioSlot
);
260 // If *ioSlot is non-nil, that node is released by CutWeakRef() and
261 // then zeroed out. Then if me is non-nil, this is acquired by
262 // calling AddWeakRef(), and if positive is returned to show success,
263 // then this is put into slot *ioSlot. Note me can be nil, so we
264 // permit expression '((morkNode*) 0L)->SlotWeakNode(ev, &slot)'.
266 static void SlotStrongNode(morkNode
* me
, morkEnv
* ev
, morkNode
** ioSlot
);
267 // If *ioSlot is non-nil, that node is released by CutStrongRef() and
268 // then zeroed out. Then if me is non-nil, this is acquired by
269 // calling AddStrongRef(), and if positive is returned to show success,
270 // then me is put into slot *ioSlot. Note me can be nil, so we take
271 // expression 'morkNode::SlotStrongNode((morkNode*) 0, ev, &slot)'.
274 extern void // utility method very similar to morkNode::SlotStrongNode():
275 nsIMdbHeap_SlotStrongHeap(nsIMdbHeap
* self
, morkEnv
* ev
, nsIMdbHeap
** ioSlot
);
276 // If *ioSlot is non-nil, that heap is released by CutStrongRef() and
277 // then zeroed out. Then if self is non-nil, this is acquired by
278 // calling AddStrongRef(), and if the return value shows success,
279 // then self is put into slot *ioSlot. Note self can be nil, so we take
280 // expression 'nsIMdbHeap_SlotStrongHeap(0, ev, &slot)'.
282 extern void // utility method very similar to morkNode::SlotStrongNode():
283 nsIMdbFile_SlotStrongFile(nsIMdbFile
* self
, morkEnv
* ev
, nsIMdbFile
** ioSlot
);
284 // If *ioSlot is non-nil, that file is released by CutStrongRef() and
285 // then zeroed out. Then if self is non-nil, this is acquired by
286 // calling AddStrongRef(), and if the return value shows success,
287 // then self is put into slot *ioSlot. Note self can be nil, so we take
288 // expression 'nsIMdbFile_SlotStrongFile(0, ev, &slot)'.
290 extern void // utility method very similar to morkNode::SlotStrongNode():
291 nsIMdbCompare_SlotStrongCompare(nsIMdbCompare
* self
, morkEnv
* ev
,
292 nsIMdbCompare
** ioSlot
);
293 // If *ioSlot is non-nil, that compare is released by CutStrongRef() and
294 // then zeroed out. Then if self is non-nil, this is acquired by
295 // calling AddStrongRef(), and if the return value shows success,
296 // then self is put into slot *ioSlot. Note self can be nil, so we take
297 // expression 'nsIMdbCompare_SlotStrongCompare(0, ev, &slot)'.
299 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
301 #endif /* _MORKNODE_ */