mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-08-25 16:59:01 +09:00
* Part 1: make conversion CTORs explicit. Minor tweaks to conform with new(ish) static analysis rule which flags up implicit single-argument conversion constructors. * Part 2: fix a couple of double-mRefCnt declaration errors. * Part 3: Fix unsafe use of NS_ConvertASCIItoUTF16(). Tag #1273
292 lines
13 KiB
C++
292 lines
13 KiB
C++
/* -*- 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
|
|
|
|
//3456789_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
|
|
|
|
};
|
|
|
|
//3456789_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) CPP_THROW_NEW
|
|
{ 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)'.
|
|
|
|
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
|
|
#endif /* _MORKNODE_ */
|