зеркало из https://github.com/mozilla/gecko-dev.git
add these. not part of the build yet.
This commit is contained in:
Родитель
49af0dba87
Коммит
3e4dfe74cd
|
@ -0,0 +1,443 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKBEAD_
|
||||
#include "morkBead.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkBead::CloseMorkNode(morkEnv* ev) // CloseBead() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseBead(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkBead::~morkBead() // assert CloseBead() executed earlier
|
||||
{
|
||||
MORK_ASSERT(mBead_Color==0 || mNode_Usage == morkUsage_kStack );
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkBead::morkBead(mork_color inBeadColor)
|
||||
: morkNode( morkUsage_kStack )
|
||||
, mBead_Color( inBeadColor )
|
||||
{
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkBead::morkBead(const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
||||
mork_color inBeadColor)
|
||||
: morkNode( inUsage, ioHeap )
|
||||
, mBead_Color( inBeadColor )
|
||||
{
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkBead::morkBead(morkEnv* ev,
|
||||
const morkUsage& inUsage, nsIMdbHeap* ioHeap, mork_color inBeadColor)
|
||||
: morkNode(ev, inUsage, ioHeap)
|
||||
, mBead_Color( inBeadColor )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kBead;
|
||||
}
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkBead::CloseBead(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
if ( !this->IsShutNode() )
|
||||
{
|
||||
mBead_Color = 0;
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkBeadMap::CloseMorkNode(morkEnv* ev) // CloseBeadMap() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseBeadMap(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkBeadMap::~morkBeadMap() // assert CloseBeadMap() executed earlier
|
||||
{
|
||||
MORK_ASSERT(this->IsShutNode());
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkBeadMap::morkBeadMap(morkEnv* ev,
|
||||
const morkUsage& inUsage, nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
|
||||
: morkMap(ev, inUsage, ioHeap, sizeof(morkBead*), /*inValSize*/ 0,
|
||||
/*slotCount*/ 11, ioSlotHeap, /*holdChanges*/ morkBool_kFalse)
|
||||
{
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kBeadMap;
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkBeadMap::CloseBeadMap(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
this->CutAllBeads(ev);
|
||||
this->CloseMap(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
mork_bool
|
||||
morkBeadMap::AddBead(morkEnv* ev, morkBead* ioBead)
|
||||
// the AddBead() boolean return equals ev->Good().
|
||||
{
|
||||
if ( ioBead && ev->Good() )
|
||||
{
|
||||
morkBead* oldBead = 0; // old key in the map
|
||||
|
||||
mork_bool put = this->Put(ev, &ioBead, /*val*/ (void*) 0,
|
||||
/*key*/ &oldBead, /*val*/ (void*) 0, (mork_change**) 0);
|
||||
|
||||
if ( put ) // replaced an existing key?
|
||||
{
|
||||
if ( oldBead && oldBead != ioBead ) // need to release old node?
|
||||
oldBead->CutStrongRef(ev);
|
||||
}
|
||||
}
|
||||
else if ( !ioBead )
|
||||
ev->NilPointerError();
|
||||
|
||||
return ev->Good();
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkBeadMap::CutBead(morkEnv* ev, mork_color inColor)
|
||||
{
|
||||
morkBead* oldBead = 0; // old key in the map
|
||||
morkBead bead(inColor);
|
||||
morkBead* key = &bead;
|
||||
|
||||
mork_bool outCutNode = this->Cut(ev, &key,
|
||||
/*key*/ &oldBead, /*val*/ (void*) 0, (mork_change**) 0);
|
||||
|
||||
if ( oldBead )
|
||||
oldBead->CutStrongRef(ev);
|
||||
|
||||
bead.CloseBead(ev);
|
||||
return outCutNode;
|
||||
}
|
||||
|
||||
morkBead*
|
||||
morkBeadMap::GetBead(morkEnv* ev, mork_color inColor)
|
||||
// Note the returned bead does NOT have an increase in refcount for this.
|
||||
{
|
||||
morkBead* oldBead = 0; // old key in the map
|
||||
morkBead bead(inColor);
|
||||
morkBead* key = &bead;
|
||||
|
||||
this->Get(ev, &key, /*key*/ &oldBead, /*val*/ (void*) 0, (mork_change**) 0);
|
||||
|
||||
bead.CloseBead(ev);
|
||||
return oldBead;
|
||||
}
|
||||
|
||||
mork_num
|
||||
morkBeadMap::CutAllBeads(morkEnv* ev)
|
||||
// CutAllBeads() releases all the referenced beads.
|
||||
{
|
||||
mork_num outSlots = mMap_Slots;
|
||||
|
||||
morkBeadMapIter i(ev, this);
|
||||
morkBead* b = i.FirstBead(ev);
|
||||
|
||||
while ( b )
|
||||
{
|
||||
b->CutStrongRef(ev);
|
||||
i.CutHereBead(ev);
|
||||
b = i.NextBead(ev);
|
||||
}
|
||||
|
||||
return outSlots;
|
||||
}
|
||||
|
||||
|
||||
// { ===== begin morkMap poly interface =====
|
||||
/*virtual*/ mork_bool
|
||||
morkBeadMap::Equal(morkEnv* ev, const void* inKeyA, const void* inKeyB) const
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
return (*(const morkBead**) inKeyA)->BeadEqual(
|
||||
*(const morkBead**) inKeyB);
|
||||
}
|
||||
|
||||
/*virtual*/ mork_u4
|
||||
morkBeadMap::Hash(morkEnv* ev, const void* inKey) const
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
return (*(const morkBead**) inKey)->BeadHash();
|
||||
}
|
||||
// } ===== end morkMap poly interface =====
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
||||
morkBead* morkBeadMapIter::FirstBead(morkEnv* ev)
|
||||
{
|
||||
morkBead* bead = 0;
|
||||
this->First(ev, &bead, /*val*/ (void*) 0);
|
||||
return bead;
|
||||
}
|
||||
|
||||
morkBead* morkBeadMapIter::NextBead(morkEnv* ev)
|
||||
{
|
||||
morkBead* bead = 0;
|
||||
this->Next(ev, &bead, /*val*/ (void*) 0);
|
||||
return bead;
|
||||
}
|
||||
|
||||
morkBead* morkBeadMapIter::HereBead(morkEnv* ev)
|
||||
{
|
||||
morkBead* bead = 0;
|
||||
this->Here(ev, &bead, /*val*/ (void*) 0);
|
||||
return bead;
|
||||
}
|
||||
|
||||
void morkBeadMapIter::CutHereBead(morkEnv* ev)
|
||||
{
|
||||
this->CutHere(ev, /*key*/ (void*) 0, /*val*/ (void*) 0);
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkBeadProbeMap::CloseMorkNode(morkEnv* ev) // CloseBeadProbeMap() if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseBeadProbeMap(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkBeadProbeMap::~morkBeadProbeMap() // assert CloseBeadProbeMap() earlier
|
||||
{
|
||||
MORK_ASSERT(this->IsShutNode());
|
||||
}
|
||||
|
||||
|
||||
/*public non-poly*/
|
||||
morkBeadProbeMap::morkBeadProbeMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
|
||||
: morkProbeMap(ev, inUsage, ioHeap,
|
||||
/*inKeySize*/ sizeof(morkBead*), /*inValSize*/ 0,
|
||||
ioSlotHeap, /*startSlotCount*/ 11,
|
||||
/*inZeroIsClearKey*/ morkBool_kTrue)
|
||||
{
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kBeadProbeMap;
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkBeadProbeMap::CloseBeadProbeMap(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
this->CutAllBeads(ev);
|
||||
this->CloseProbeMap(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
/*virtual*/ mork_test // hit(a,b) implies hash(a) == hash(b)
|
||||
morkBeadProbeMap::MapTest(morkEnv* ev, const void* inMapKey,
|
||||
const void* inAppKey) const
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
const morkBead* key = *(const morkBead**) inMapKey;
|
||||
if ( key )
|
||||
{
|
||||
mork_bool hit = key->BeadEqual(*(const morkBead**) inAppKey);
|
||||
return ( hit ) ? morkTest_kHit : morkTest_kMiss;
|
||||
}
|
||||
else
|
||||
return morkTest_kVoid;
|
||||
}
|
||||
|
||||
/*virtual*/ mork_u4 // hit(a,b) implies hash(a) == hash(b)
|
||||
morkBeadProbeMap::MapHash(morkEnv* ev, const void* inAppKey) const
|
||||
{
|
||||
const morkBead* key = *(const morkBead**) inAppKey;
|
||||
if ( key )
|
||||
return key->BeadHash();
|
||||
else
|
||||
{
|
||||
ev->NilPointerWarning();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ mork_u4
|
||||
morkBeadProbeMap::ProbeMapHashMapKey(morkEnv* ev,
|
||||
const void* inMapKey) const
|
||||
{
|
||||
const morkBead* key = *(const morkBead**) inMapKey;
|
||||
if ( key )
|
||||
return key->BeadHash();
|
||||
else
|
||||
{
|
||||
ev->NilPointerWarning();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkBeadProbeMap::AddBead(morkEnv* ev, morkBead* ioBead)
|
||||
{
|
||||
if ( ioBead && ev->Good() )
|
||||
{
|
||||
morkBead* bead = 0; // old key in the map
|
||||
|
||||
mork_bool put = this->MapAtPut(ev, &ioBead, /*val*/ (void*) 0,
|
||||
/*key*/ &bead, /*val*/ (void*) 0);
|
||||
|
||||
if ( put ) // replaced an existing key?
|
||||
{
|
||||
if ( bead && bead != ioBead ) // need to release old node?
|
||||
bead->CutStrongRef(ev);
|
||||
}
|
||||
}
|
||||
else if ( !ioBead )
|
||||
ev->NilPointerError();
|
||||
|
||||
return ev->Good();
|
||||
}
|
||||
|
||||
morkBead*
|
||||
morkBeadProbeMap::GetBead(morkEnv* ev, mork_color inColor)
|
||||
{
|
||||
morkBead* oldBead = 0; // old key in the map
|
||||
morkBead bead(inColor);
|
||||
morkBead* key = &bead;
|
||||
|
||||
this->MapAt(ev, &key, &oldBead, /*val*/ (void*) 0);
|
||||
|
||||
bead.CloseBead(ev);
|
||||
return oldBead;
|
||||
}
|
||||
|
||||
mork_num
|
||||
morkBeadProbeMap::CutAllBeads(morkEnv* ev)
|
||||
// CutAllBeads() releases all the referenced bead values.
|
||||
{
|
||||
mork_num outSlots = sMap_Slots;
|
||||
|
||||
morkBeadProbeMapIter i(ev, this);
|
||||
morkBead* b = i.FirstBead(ev);
|
||||
|
||||
while ( b )
|
||||
{
|
||||
b->CutStrongRef(ev);
|
||||
b = i.NextBead(ev);
|
||||
}
|
||||
this->MapCutAll(ev);
|
||||
|
||||
return outSlots;
|
||||
}
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
|
@ -0,0 +1,258 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MORKBEAD_
|
||||
#define _MORKBEAD_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKMAP_
|
||||
#include "morkMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKPROBEMAP_
|
||||
#include "morkProbeMap.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kBead /*i*/ 0x426F /* ascii 'Bo' */
|
||||
|
||||
/*| morkBead: subclass of morkNode that adds knowledge of db suite factory
|
||||
**| and containing port to those objects that are exposed as instances of
|
||||
**| nsIMdbBead in the public interface.
|
||||
|*/
|
||||
class morkBead : public morkNode {
|
||||
|
||||
// public: // slots inherited from morkNode (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
|
||||
// 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
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
mork_color mBead_Color; // ID for this bead
|
||||
|
||||
public: // Hash() and Equal() for bead maps are same for all subclasses:
|
||||
|
||||
mork_u4 BeadHash() const { return (mork_u4) mBead_Color; }
|
||||
mork_bool BeadEqual(const morkBead* inBead) const
|
||||
{ return ( mBead_Color == inBead->mBead_Color); }
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseBead() only if open
|
||||
virtual ~morkBead(); // assert that CloseBead() executed earlier
|
||||
|
||||
public: // special case for stack construction for map usage:
|
||||
morkBead(mork_color inBeadColor); // stack-based bead instance
|
||||
|
||||
protected: // special case for morkObject:
|
||||
morkBead(const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
||||
mork_color inBeadColor);
|
||||
|
||||
public: // morkEnv construction & destruction
|
||||
morkBead(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
||||
mork_color inBeadColor);
|
||||
void CloseBead(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
private: // copying is not allowed
|
||||
morkBead(const morkBead& other);
|
||||
morkBead& operator=(const morkBead& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsBead() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kBead; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
// void NewNilHandleError(morkEnv* ev); // mBead_Handle is nil
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakBead(morkBead* me,
|
||||
morkEnv* ev, morkBead** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongBead(morkBead* me,
|
||||
morkEnv* ev, morkBead** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kBeadMap /*i*/ 0x744D /* ascii 'bM' */
|
||||
|
||||
/*| morkBeadMap: maps bead -> bead (key only using mBead_Color)
|
||||
|*/
|
||||
class morkBeadMap : public morkMap {
|
||||
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseBeadMap() only if open
|
||||
virtual ~morkBeadMap(); // assert that CloseBeadMap() executed earlier
|
||||
|
||||
public: // morkMap construction & destruction
|
||||
morkBeadMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap);
|
||||
void CloseBeadMap(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsBeadMap() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kBeadMap; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
// { ===== begin morkMap poly interface =====
|
||||
public:
|
||||
virtual mork_bool // *((mork_u4*) inKeyA) == *((mork_u4*) inKeyB)
|
||||
Equal(morkEnv* ev, const void* inKeyA, const void* inKeyB) const;
|
||||
|
||||
virtual mork_u4 // some integer function of *((mork_u4*) inKey)
|
||||
Hash(morkEnv* ev, const void* inKey) const;
|
||||
// } ===== end morkMap poly interface =====
|
||||
|
||||
public: // other map methods
|
||||
|
||||
mork_bool AddBead(morkEnv* ev, morkBead* ioBead);
|
||||
// the AddBead() boolean return equals ev->Good().
|
||||
|
||||
mork_bool CutBead(morkEnv* ev, mork_color inColor);
|
||||
// The CutBead() boolean return indicates whether removal happened.
|
||||
|
||||
morkBead* GetBead(morkEnv* ev, mork_color inColor);
|
||||
// Note the returned bead does NOT have an increase in refcount for this.
|
||||
|
||||
mork_num CutAllBeads(morkEnv* ev);
|
||||
// CutAllBeads() releases all the referenced beads.
|
||||
};
|
||||
|
||||
class morkBeadMapIter: public morkMapIter{ // typesafe wrapper class
|
||||
|
||||
public:
|
||||
morkBeadMapIter(morkEnv* ev, morkBeadMap* ioMap)
|
||||
: morkMapIter(ev, ioMap) { }
|
||||
|
||||
morkBeadMapIter( ) : morkMapIter() { }
|
||||
void InitBeadMapIter(morkEnv* ev, morkBeadMap* ioMap)
|
||||
{ this->InitMapIter(ev, ioMap); }
|
||||
|
||||
morkBead* FirstBead(morkEnv* ev);
|
||||
morkBead* NextBead(morkEnv* ev);
|
||||
morkBead* HereBead(morkEnv* ev);
|
||||
void CutHereBead(morkEnv* ev);
|
||||
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kBeadProbeMap /*i*/ 0x6D74 /* ascii 'mb' */
|
||||
|
||||
/*| morkBeadProbeMap: maps bead -> bead (key only using mBead_Color)
|
||||
|*/
|
||||
class morkBeadProbeMap : public morkProbeMap {
|
||||
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseBeadProbeMap() only if open
|
||||
virtual ~morkBeadProbeMap(); // assert that CloseBeadProbeMap() executed earlier
|
||||
|
||||
public: // morkMap construction & destruction
|
||||
morkBeadProbeMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap);
|
||||
void CloseBeadProbeMap(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsBeadProbeMap() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kBeadProbeMap; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
// { ===== begin morkProbeMap methods =====
|
||||
public:
|
||||
virtual mork_test // hit(a,b) implies hash(a) == hash(b)
|
||||
MapTest(morkEnv* ev, const void* inMapKey, const void* inAppKey) const;
|
||||
|
||||
virtual mork_u4 // hit(a,b) implies hash(a) == hash(b)
|
||||
MapHash(morkEnv* ev, const void* inAppKey) const;
|
||||
|
||||
virtual mork_u4 ProbeMapHashMapKey(morkEnv* ev, const void* inMapKey) const;
|
||||
|
||||
// virtual mork_bool ProbeMapIsKeyNil(morkEnv* ev, void* ioMapKey);
|
||||
|
||||
// virtual void ProbeMapClearKey(morkEnv* ev, // put 'nil' alls keys inside map
|
||||
// void* ioMapKey, mork_count inKeyCount); // array of keys inside map
|
||||
|
||||
// virtual void ProbeMapPushIn(morkEnv* ev, // move (key,val) into the map
|
||||
// const void* inAppKey, const void* inAppVal, // (key,val) outside map
|
||||
// void* outMapKey, void* outMapVal); // (key,val) inside map
|
||||
|
||||
// virtual void ProbeMapPullOut(morkEnv* ev, // move (key,val) out from the map
|
||||
// const void* inMapKey, const void* inMapVal, // (key,val) inside map
|
||||
// void* outAppKey, void* outAppVal) const; // (key,val) outside map
|
||||
// } ===== end morkProbeMap methods =====
|
||||
|
||||
public: // other map methods
|
||||
|
||||
mork_bool AddBead(morkEnv* ev, morkBead* ioBead);
|
||||
// the AddBead() boolean return equals ev->Good().
|
||||
|
||||
morkBead* GetBead(morkEnv* ev, mork_color inColor);
|
||||
// Note the returned bead does NOT have an increase in refcount for this.
|
||||
|
||||
mork_num CutAllBeads(morkEnv* ev);
|
||||
// CutAllBeads() releases all the referenced bead values.
|
||||
};
|
||||
|
||||
class morkBeadProbeMapIter: public morkProbeMapIter { // typesafe wrapper class
|
||||
|
||||
public:
|
||||
morkBeadProbeMapIter(morkEnv* ev, morkBeadProbeMap* ioMap)
|
||||
: morkProbeMapIter(ev, ioMap) { }
|
||||
|
||||
morkBeadProbeMapIter( ) : morkProbeMapIter() { }
|
||||
void InitBeadProbeMapIter(morkEnv* ev, morkBeadProbeMap* ioMap)
|
||||
{ this->InitProbeMapIter(ev, ioMap); }
|
||||
|
||||
morkBead* FirstBead(morkEnv* ev)
|
||||
{ return (morkBead*) this->IterFirstKey(ev); }
|
||||
|
||||
morkBead* NextBead(morkEnv* ev)
|
||||
{ return (morkBead*) this->IterNextKey(ev); }
|
||||
|
||||
morkBead* HereBead(morkEnv* ev)
|
||||
{ return (morkBead*) this->IterHereKey(ev); }
|
||||
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKBEAD_ */
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,414 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
// This code is a port to NS Mork from public domain Mithril C++ sources.
|
||||
// Note many code comments here come verbatim from cut-and-pasted Mithril.
|
||||
// In many places, code is identical; Mithril versions stay public domain.
|
||||
// Changes in porting are mainly class type and scalar type name changes.
|
||||
|
||||
#ifndef _MORKPROBEMAP_
|
||||
#define _MORKPROBEMAP_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
class morkMapScratch { // utility class used by map subclasses
|
||||
public:
|
||||
nsIMdbHeap* sMapScratch_Heap; // cached sMap_Heap
|
||||
mork_count sMapScratch_Slots; // cached sMap_Slots
|
||||
|
||||
mork_u1* sMapScratch_Keys; // cached sMap_Keys
|
||||
mork_u1* sMapScratch_Vals; // cached sMap_Vals
|
||||
|
||||
public:
|
||||
void halt_map_scratch(morkEnv* ev);
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kProbeMap 0x7072 /* ascii 'pr' */
|
||||
#define morkProbeMap_kTag 0x70724D50 /* ascii 'prMP' */
|
||||
|
||||
#define morkProbeMap_kLazyClearOnAdd ((mork_u1) 'c')
|
||||
|
||||
class morkProbeMap: public morkNode {
|
||||
|
||||
protected:
|
||||
|
||||
// public: // slots inherited from morkNode (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
|
||||
// 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:
|
||||
// { begin morkMap slots
|
||||
nsIMdbHeap* sMap_Heap; // strong ref to heap allocating all space
|
||||
|
||||
mork_u1* sMap_Keys;
|
||||
mork_u1* sMap_Vals;
|
||||
|
||||
mork_count sMap_Seed; // change count of members or structure
|
||||
|
||||
mork_count sMap_Slots; // count of slots in the hash table
|
||||
mork_fill sMap_Fill; // number of used slots in the hash table
|
||||
|
||||
mork_size sMap_KeySize; // size of each key (cannot be zero)
|
||||
mork_size sMap_ValSize; // size of each val (zero allowed)
|
||||
|
||||
mork_bool sMap_KeyIsIP; // sMap_KeySize == sizeof(mork_ip)
|
||||
mork_bool sMap_ValIsIP; // sMap_ValSize == sizeof(mork_ip)
|
||||
mork_u1 sMap_Pad[ 2 ]; // for u4 alignment
|
||||
// } end morkMap slots
|
||||
|
||||
friend class morkProbeMapIter; // for access to protected slots
|
||||
|
||||
public: // getters
|
||||
mork_count MapSeed() const { return sMap_Seed; }
|
||||
|
||||
mork_count MapSlots() const { return sMap_Slots; }
|
||||
mork_fill MapFill() const { return sMap_Fill; }
|
||||
|
||||
mork_size MapKeySize() const { return sMap_KeySize; }
|
||||
mork_size MapValSize() const { return sMap_ValSize; }
|
||||
|
||||
mork_bool MapKeyIsIP() const { return sMap_KeyIsIP; }
|
||||
mork_bool MapValIsIP() const { return sMap_ValIsIP; }
|
||||
|
||||
protected: // slots
|
||||
// { begin morkProbeMap slots
|
||||
|
||||
mork_fill sProbeMap_MaxFill; // max sMap_Fill before map must grow
|
||||
|
||||
mork_u1 sProbeMap_LazyClearOnAdd; // true if kLazyClearOnAdd
|
||||
mork_bool sProbeMap_ZeroIsClearKey; // zero is adequate to clear keys
|
||||
mork_u1 sProbeMap_Pad[ 2 ]; // for u4 alignment
|
||||
|
||||
mork_u4 sProbeMap_Tag;
|
||||
|
||||
// } end morkProbeMap slots
|
||||
|
||||
friend class morkProbeMapIter; // for access to protected slots
|
||||
|
||||
public: // lazy clear on add
|
||||
|
||||
mork_bool need_lazy_init() const
|
||||
{ return sProbeMap_LazyClearOnAdd == morkProbeMap_kLazyClearOnAdd; }
|
||||
|
||||
public: // typing
|
||||
mork_bool GoodProbeMap() const
|
||||
{ return sProbeMap_Tag == morkProbeMap_kTag; }
|
||||
|
||||
protected: // utilities
|
||||
|
||||
void* clear_alloc(morkEnv* ev, mork_size inSize);
|
||||
|
||||
mork_u1* map_new_vals(morkEnv* ev, mork_num inSlots);
|
||||
mork_u1* map_new_keys(morkEnv* ev, mork_num inSlots);
|
||||
|
||||
void clear_probe_map(morkEnv* ev, nsIMdbHeap* ioMapHeap);
|
||||
void init_probe_map(morkEnv* ev, mork_size inSlots);
|
||||
void probe_map_lazy_init(morkEnv* ev);
|
||||
|
||||
mork_bool new_slots(morkEnv* ev, morkMapScratch* old, mork_num inSlots);
|
||||
|
||||
mork_test find_key_pos(morkEnv* ev, const void* inAppKey,
|
||||
mork_u4 inHash, mork_pos* outPos) const;
|
||||
|
||||
void put_probe_kv(morkEnv* ev,
|
||||
const void* inAppKey, const void* inAppVal, mork_pos inPos);
|
||||
void get_probe_kv(morkEnv* ev,
|
||||
void* outAppKey, void* outAppVal, mork_pos inPos) const;
|
||||
|
||||
mork_bool grow_probe_map(morkEnv* ev);
|
||||
void rehash_old_map(morkEnv* ev, morkMapScratch* ioScratch);
|
||||
void revert_map(morkEnv* ev, morkMapScratch* ioScratch);
|
||||
|
||||
public: // errors
|
||||
void ProbeMapBadTagError(morkEnv* ev) const;
|
||||
void WrapWithNoVoidSlotError(morkEnv* ev) const;
|
||||
void GrowFailsMaxFillError(morkEnv* ev) const;
|
||||
void MapKeyIsNotIPError(morkEnv* ev) const;
|
||||
void MapValIsNotIPError(morkEnv* ev) const;
|
||||
|
||||
void MapNilKeysError(morkEnv* ev);
|
||||
void MapZeroKeySizeError(morkEnv* ev);
|
||||
|
||||
void MapSeedOutOfSyncError(morkEnv* ev);
|
||||
void MapFillUnderflowWarning(morkEnv* ev);
|
||||
|
||||
static void ProbeMapCutError(morkEnv* ev);
|
||||
|
||||
// { ===== begin morkMap methods =====
|
||||
public:
|
||||
|
||||
virtual mork_test // hit(a,b) implies hash(a) == hash(b)
|
||||
MapTest(morkEnv* ev, const void* inMapKey, const void* inAppKey) const;
|
||||
// Note inMapKey is always a key already stored in the map, while inAppKey
|
||||
// is always a method argument parameter from a client method call.
|
||||
// This matters the most in morkProbeMap subclasses, which have the
|
||||
// responsibility of putting 'app' keys into slots for 'map' keys, and
|
||||
// the bit pattern representation might be different in such cases.
|
||||
// morkTest_kHit means that inMapKey equals inAppKey (and this had better
|
||||
// also imply that hash(inMapKey) == hash(inAppKey)).
|
||||
// morkTest_kMiss means that inMapKey does NOT equal inAppKey (but this
|
||||
// implies nothing at all about hash(inMapKey) and hash(inAppKey)).
|
||||
// morkTest_kVoid means that inMapKey is not a valid key bit pattern,
|
||||
// which means that key slot in the map is not being used. Note that
|
||||
// kVoid is only expected as a return value in morkProbeMap subclasses,
|
||||
// because morkProbeMap must ask whether a key slot is used or not.
|
||||
// morkChainMap however, always knows when a key slot is used, so only
|
||||
// key slots expected to have valid bit patterns will be presented to
|
||||
// the MapTest() methods for morkChainMap subclasses.
|
||||
//
|
||||
// NOTE: it is very important that subclasses correctly return the value
|
||||
// morkTest_kVoid whenever the slot for inMapKey contains a bit pattern
|
||||
// that means the slot is not being used, because this is the only way a
|
||||
// probe map can terminate an unsuccessful search for a key in the map.
|
||||
|
||||
virtual mork_u4 // hit(a,b) implies hash(a) == hash(b)
|
||||
MapHash(morkEnv* ev, const void* inAppKey) const;
|
||||
|
||||
virtual mork_bool
|
||||
MapAtPut(morkEnv* ev, const void* inAppKey, const void* inAppVal,
|
||||
void* outAppKey, void* outAppVal);
|
||||
|
||||
virtual mork_bool
|
||||
MapAt(morkEnv* ev, const void* inAppKey, void* outAppKey, void* outAppVal);
|
||||
|
||||
virtual mork_num
|
||||
MapCutAll(morkEnv* ev);
|
||||
// } ===== end morkMap methods =====
|
||||
|
||||
|
||||
// { ===== begin morkProbeMap methods =====
|
||||
public:
|
||||
|
||||
virtual mork_u4
|
||||
ProbeMapHashMapKey(morkEnv* ev, const void* inMapKey) const;
|
||||
// ProbeMapHashMapKey() does logically the same thing as MapHash(), and
|
||||
// the default implementation actually calls virtual MapHash(). However,
|
||||
// Subclasses must override this method whenever the formats of keys in
|
||||
// the map differ from app keys outside the map, because MapHash() only
|
||||
// works on keys in 'app' format, while ProbeMapHashMapKey() only works
|
||||
// on keys in 'map' format. This method is called in order to rehash all
|
||||
// map keys when a map is grown, and this causes all old map members to
|
||||
// move into new slot locations.
|
||||
//
|
||||
// Note it is absolutely imperative that a hash for a key in 'map' format
|
||||
// be exactly the same the hash of the same key in 'app' format, or else
|
||||
// maps will seem corrupt later when keys in 'app' format cannot be found.
|
||||
|
||||
virtual mork_bool
|
||||
ProbeMapIsKeyNil(morkEnv* ev, void* ioMapKey);
|
||||
// ProbeMapIsKeyNil() must say whether the representation of logical 'nil'
|
||||
// is currently found inside the key at ioMapKey, for a key found within
|
||||
// the map. The the map iterator uses this method to find map keys that
|
||||
// are actually being used for valid map associations; otherwise the
|
||||
// iterator cannot determine which map slots actually denote used keys.
|
||||
// The default method version returns true if all the bits equal zero.
|
||||
|
||||
virtual void
|
||||
ProbeMapClearKey(morkEnv* ev, // put 'nil' alls keys inside map
|
||||
void* ioMapKey, mork_count inKeyCount); // array of keys inside map
|
||||
// ProbeMapClearKey() must put some representation of logical 'nil' into
|
||||
// every key slot in the map, such that MapTest() will later recognize
|
||||
// that this bit pattern shows each key slot is not actually being used.
|
||||
//
|
||||
// This method is typically called whenever the map is either created or
|
||||
// grown into a larger size, where ioMapKey is a pointer to an array of
|
||||
// inKeyCount keys, where each key is this->MapKeySize() bytes in size.
|
||||
// Note that keys are assumed immediately adjacent with no padding, so
|
||||
// if any alignment requirements must be met, then subclasses should have
|
||||
// already accounted for this when specifying a key size in the map.
|
||||
//
|
||||
// Since this method will be called when a map is being grown in size,
|
||||
// nothing should be assumed about the state slots of the map, since the
|
||||
// ioMapKey array might not yet live in sMap_Keys, and the array length
|
||||
// inKeyCount might not yet live in sMap_Slots. However, the value kept
|
||||
// in sMap_KeySize never changes, so this->MapKeySize() is always correct.
|
||||
|
||||
virtual void
|
||||
ProbeMapPushIn(morkEnv* ev, // move (key,val) into the map
|
||||
const void* inAppKey, const void* inAppVal, // (key,val) outside map
|
||||
void* outMapKey, void* outMapVal); // (key,val) inside map
|
||||
// This method actually puts keys and vals in the map in suitable format.
|
||||
//
|
||||
// ProbeMapPushIn() must copy a caller key and value in 'app' format
|
||||
// into the map slots provided, which are in 'map' format. When the
|
||||
// 'app' and 'map' formats are identical, then this is just a bitwise
|
||||
// copy of this->MapKeySize() key bytes and this->MapValSize() val bytes,
|
||||
// and this is exactly what the default implementation performs. However,
|
||||
// if 'app' and 'map' formats are different, and MapTest() depends on this
|
||||
// difference in format, then subclasses must override this method to do
|
||||
// whatever is necessary to store the input app key in output map format.
|
||||
//
|
||||
// Do NOT write more than this->MapKeySize() bytes of a map key, or more
|
||||
// than this->MapValSize() bytes of a map val, or corruption might ensue.
|
||||
//
|
||||
// The inAppKey and inAppVal parameters are the same ones passed into a
|
||||
// call to MapAtPut(), and the outMapKey and outMapVal parameters are ones
|
||||
// determined by how the map currently positions key inAppKey in the map.
|
||||
//
|
||||
// Note any key or val parameter can be a null pointer, in which case
|
||||
// this method must do nothing with those parameters. In particular, do
|
||||
// no key move at all when either inAppKey or outMapKey is nil, and do
|
||||
// no val move at all when either inAppVal or outMapVal is nil. Note that
|
||||
// outMapVal should always be nil when this->MapValSize() is nil.
|
||||
|
||||
virtual void
|
||||
ProbeMapPullOut(morkEnv* ev, // move (key,val) out from the map
|
||||
const void* inMapKey, const void* inMapVal, // (key,val) inside map
|
||||
void* outAppKey, void* outAppVal) const; // (key,val) outside map
|
||||
// This method actually gets keys and vals from the map in suitable format.
|
||||
//
|
||||
// ProbeMapPullOut() must copy a key and val in 'map' format into the
|
||||
// caller key and val slots provided, which are in 'app' format. When the
|
||||
// 'app' and 'map' formats are identical, then this is just a bitwise
|
||||
// copy of this->MapKeySize() key bytes and this->MapValSize() val bytes,
|
||||
// and this is exactly what the default implementation performs. However,
|
||||
// if 'app' and 'map' formats are different, and MapTest() depends on this
|
||||
// difference in format, then subclasses must override this method to do
|
||||
// whatever is necessary to store the input map key in output app format.
|
||||
//
|
||||
// The outAppKey and outAppVal parameters are the same ones passed into a
|
||||
// call to either MapAtPut() or MapAt(), while inMapKey and inMapVal are
|
||||
// determined by how the map currently positions the target key in the map.
|
||||
//
|
||||
// Note any key or val parameter can be a null pointer, in which case
|
||||
// this method must do nothing with those parameters. In particular, do
|
||||
// no key move at all when either inMapKey or outAppKey is nil, and do
|
||||
// no val move at all when either inMapVal or outAppVal is nil. Note that
|
||||
// inMapVal should always be nil when this->MapValSize() is nil.
|
||||
|
||||
// } ===== end morkProbeMap methods =====
|
||||
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseProbeMap() only if open
|
||||
virtual ~morkProbeMap(); // assert that CloseProbeMap() executed earlier
|
||||
|
||||
public: // morkProbeMap construction & destruction
|
||||
morkProbeMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioNodeHeap,
|
||||
mork_size inKeySize, mork_size inValSize,
|
||||
nsIMdbHeap* ioMapHeap, mork_size inSlots,
|
||||
mork_bool inZeroIsClearKey);
|
||||
|
||||
void CloseProbeMap(morkEnv* ev); // called by
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsProbeMap() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kProbeMap; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakMap(morkMap* me,
|
||||
morkEnv* ev, morkMap** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongMap(morkMap* me,
|
||||
morkEnv* ev, morkMap** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
/*============================================================================*/
|
||||
/* morkProbeMapIter */
|
||||
|
||||
#define morkProbeMapIter_kBeforeIx ((mork_i4) -1) /* before first member */
|
||||
#define morkProbeMapIter_kAfterIx ((mork_i4) -2) /* after last member */
|
||||
|
||||
class morkProbeMapIter {
|
||||
|
||||
protected:
|
||||
morkProbeMap* sProbeMapIter_Map; // nonref
|
||||
mork_num sProbeMapIter_Seed; // iter's cached copy of map's seed
|
||||
|
||||
mork_i4 sProbeMapIter_HereIx;
|
||||
|
||||
mork_change sProbeMapIter_Change; // morkMapIter API simulation dummy
|
||||
mork_u1 sProbeMapIter_Pad[ 3 ]; // for u4 alignment
|
||||
|
||||
public:
|
||||
morkProbeMapIter(morkEnv* ev, morkProbeMap* ioMap);
|
||||
void CloseMapIter(morkEnv* ev);
|
||||
|
||||
morkProbeMapIter( ); // zero most slots; caller must call InitProbeMapIter()
|
||||
|
||||
protected: // protected so subclasses must provide suitable typesafe inlines:
|
||||
|
||||
void InitProbeMapIter(morkEnv* ev, morkProbeMap* ioMap);
|
||||
|
||||
void InitMapIter(morkEnv* ev, morkProbeMap* ioMap) // morkMapIter compatibility
|
||||
{ this->InitProbeMapIter(ev, ioMap); }
|
||||
|
||||
mork_bool IterFirst(morkEnv* ev, void* outKey, void* outVal);
|
||||
mork_bool IterNext(morkEnv* ev, void* outKey, void* outVal);
|
||||
mork_bool IterHere(morkEnv* ev, void* outKey, void* outVal);
|
||||
|
||||
// NOTE: the following methods ONLY work for sMap_ValIsIP pointer values.
|
||||
// (Note the implied assumption that zero is never a good value pattern.)
|
||||
|
||||
void* IterFirstVal(morkEnv* ev, void* outKey);
|
||||
// equivalent to { void* v=0; this->IterFirst(ev, outKey, &v); return v; }
|
||||
|
||||
void* IterNextVal(morkEnv* ev, void* outKey);
|
||||
// equivalent to { void* v=0; this->IterNext(ev, outKey, &v); return v; }
|
||||
|
||||
void* IterHereVal(morkEnv* ev, void* outKey);
|
||||
// equivalent to { void* v=0; this->IterHere(ev, outKey, &v); return v; }
|
||||
|
||||
// NOTE: the following methods ONLY work for sMap_KeyIsIP pointer values.
|
||||
// (Note the implied assumption that zero is never a good key pattern.)
|
||||
|
||||
void* IterFirstKey(morkEnv* ev);
|
||||
// equivalent to { void* k=0; this->IterFirst(ev, &k, 0); return k; }
|
||||
|
||||
void* IterNextKey(morkEnv* ev);
|
||||
// equivalent to { void* k=0; this->IterNext(ev, &k, 0); return k; }
|
||||
|
||||
void* IterHereKey(morkEnv* ev);
|
||||
// equivalent to { void* k=0; this->IterHere(ev, &k, 0); return k; }
|
||||
|
||||
public: // simulation of the morkMapIter API for morkMap compatibility:
|
||||
mork_change* First(morkEnv* ev, void* outKey, void* outVal);
|
||||
mork_change* Next(morkEnv* ev, void* outKey, void* outVal);
|
||||
mork_change* Here(morkEnv* ev, void* outKey, void* outVal);
|
||||
|
||||
mork_change* CutHere(morkEnv* ev, void* outKey, void* outVal);
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKPROBEMAP_ */
|
|
@ -0,0 +1,557 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKZONE_
|
||||
#include "morkZone.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
// public: // morkNode virtual methods
|
||||
void morkZone::CloseMorkNode(morkEnv* ev) // CloseZone() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseZone(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
morkZone::~morkZone() // assert that CloseZone() executed earlier
|
||||
{
|
||||
MORK_ASSERT(this->IsShutNode());
|
||||
}
|
||||
|
||||
// public: // morkMap construction & destruction
|
||||
morkZone::morkZone(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioNodeHeap, nsIMdbHeap* ioZoneHeap)
|
||||
: morkNode(ev, inUsage, ioNodeHeap)
|
||||
, mZone_Heap( 0 )
|
||||
, mZone_HeapVolume( 0 )
|
||||
, mZone_BlockVolume( 0 )
|
||||
, mZone_RunVolume( 0 )
|
||||
, mZone_ChipVolume( 0 )
|
||||
|
||||
, mZone_FreeOldRunVolume( 0 )
|
||||
|
||||
, mZone_HunkCount( 0 )
|
||||
, mZone_FreeOldRunCount( 0 )
|
||||
|
||||
, mZone_HunkList( 0 )
|
||||
, mZone_FreeOldRunList( 0 )
|
||||
|
||||
, mZone_At( 0 )
|
||||
, mZone_AtSize( 0 )
|
||||
|
||||
// morkRun* mZone_FreeRuns[ morkZone_kBuckets + 1 ];
|
||||
{
|
||||
|
||||
morkRun** runs = mZone_FreeRuns;
|
||||
morkRun** end = runs + (morkZone_kBuckets + 1); // one past last slot
|
||||
--runs; // prepare for preincrement
|
||||
while ( ++runs < end ) // another slot in array?
|
||||
*runs = 0; // clear all the slots
|
||||
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( ioZoneHeap )
|
||||
{
|
||||
nsIMdbHeap_SlotStrongHeap(ioZoneHeap, ev, &mZone_Heap);
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kZone;
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
}
|
||||
|
||||
void morkZone::CloseZone(morkEnv* ev) // called by CloseMorkNode()
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
nsIMdbHeap* heap = mZone_Heap;
|
||||
if ( heap )
|
||||
{
|
||||
morkHunk* hunk = 0;
|
||||
nsIMdbEnv* mev = ev->AsMdbEnv();
|
||||
|
||||
morkHunk* next = mZone_HunkList;
|
||||
while ( ( hunk = next ) != 0 )
|
||||
{
|
||||
#ifdef morkHunk_USE_TAG_SLOT
|
||||
if ( !hunk->HunkGoodTag() )
|
||||
hunk->BadHunkTagWarning(ev);
|
||||
#endif /* morkHunk_USE_TAG_SLOT */
|
||||
|
||||
next = hunk->HunkNext();
|
||||
heap->Free(mev, hunk);
|
||||
}
|
||||
}
|
||||
nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*) 0, ev, &mZone_Heap);
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
/*static*/ void
|
||||
morkZone::NonZoneTypeError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("non morkZone");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkZone::NilZoneHeapError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("nil mZone_Heap");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkHunk::BadHunkTagWarning(morkEnv* ev)
|
||||
{
|
||||
ev->NewWarning("bad mHunk_Tag");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkRun::BadRunTagError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("bad mRun_Tag");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkRun::RunSizeAlignError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("bad RunSize() alignment");
|
||||
}
|
||||
|
||||
// { ===== begin morkZone methods =====
|
||||
|
||||
|
||||
mork_size morkZone::zone_grow_at(morkEnv* ev, mork_size inNeededSize)
|
||||
{
|
||||
mZone_At = 0; // remove any ref to current hunk
|
||||
mZone_AtSize = 0; // zero available bytes in current hunk
|
||||
|
||||
mork_size runSize = 0; // actual size of a particular run
|
||||
|
||||
// try to find a run in old run list with at least inNeededSize bytes:
|
||||
morkRun* run = mZone_FreeOldRunList; // cursor in list scan
|
||||
morkRun* prev = 0; // the node before run in the list scan
|
||||
|
||||
while ( run ) // another run in list to check?
|
||||
{
|
||||
morkOldRun* oldRun = (morkOldRun*) run;
|
||||
mork_size oldSize = oldRun->OldSize();
|
||||
if ( oldSize >= inNeededSize ) // found one big enough?
|
||||
{
|
||||
runSize = oldSize;
|
||||
break; // end while loop early
|
||||
}
|
||||
prev = run; // remember last position in singly linked list
|
||||
run = run->RunNext(); // advance cursor to next node in list
|
||||
}
|
||||
if ( runSize && run ) // found a usable old run?
|
||||
{
|
||||
morkRun* next = run->RunNext();
|
||||
if ( prev ) // another node in free list precedes run?
|
||||
prev->RunSetNext(next); // unlink run
|
||||
else
|
||||
mZone_FreeOldRunList = run; // unlink run from head of list
|
||||
|
||||
run->RunSetSize(runSize);
|
||||
mZone_At = (mork_u1*) run->RunAsBlock();
|
||||
mZone_AtSize = runSize;
|
||||
|
||||
#ifdef morkZone_CONFIG_DEBUG
|
||||
#ifdef morkZone_CONFIG_ALIGN_8
|
||||
mork_ip lowThree = ((mork_ip) mZone_At) & 7;
|
||||
if ( lowThree ) // not 8 byte aligned?
|
||||
#else /*morkZone_CONFIG_ALIGN_8*/
|
||||
mork_ip lowTwo = ((mork_ip) mZone_At) & 3;
|
||||
if ( lowTwo ) // not 4 byte aligned?
|
||||
#endif /*morkZone_CONFIG_ALIGN_8*/
|
||||
ev->NewWarning("mZone_At not aligned");
|
||||
#endif /*morkZone_CONFIG_DEBUG*/
|
||||
}
|
||||
else // need to allocate a brand new run
|
||||
{
|
||||
inNeededSize += 7; // allow for possible alignment padding
|
||||
mork_size newSize = ( inNeededSize > morkZone_kNewHunkSize )?
|
||||
inNeededSize : morkZone_kNewHunkSize;
|
||||
|
||||
morkHunk* hunk = this->zone_new_hunk(ev, newSize);
|
||||
if ( hunk )
|
||||
{
|
||||
morkRun* hunkRun = hunk->HunkRun();
|
||||
mork_u1* at = (mork_u1*) hunkRun->RunAsBlock();
|
||||
mork_ip lowBits = ((mork_ip) at) & 7;
|
||||
if ( lowBits ) // not 8 byte aligned?
|
||||
{
|
||||
mork_ip skip = (8 - lowBits); // skip the complement to align
|
||||
at += skip;
|
||||
newSize -= skip;
|
||||
}
|
||||
mZone_At = at;
|
||||
mZone_AtSize = newSize;
|
||||
}
|
||||
}
|
||||
|
||||
return mZone_AtSize;
|
||||
}
|
||||
|
||||
morkHunk* morkZone::zone_new_hunk(morkEnv* ev, mdb_size inSize) // alloc
|
||||
{
|
||||
mdb_size hunkSize = inSize + sizeof(morkHunk);
|
||||
void* outBlock = 0; // we are going straight to the heap:
|
||||
mZone_Heap->Alloc(ev->AsMdbEnv(), hunkSize, &outBlock);
|
||||
if ( outBlock )
|
||||
{
|
||||
#ifdef morkZone_CONFIG_VOL_STATS
|
||||
mZone_HeapVolume += hunkSize; // track all heap allocations
|
||||
#endif /* morkZone_CONFIG_VOL_STATS */
|
||||
|
||||
morkHunk* hunk = (morkHunk*) outBlock;
|
||||
#ifdef morkHunk_USE_TAG_SLOT
|
||||
hunk->HunkInitTag();
|
||||
#endif /* morkHunk_USE_TAG_SLOT */
|
||||
|
||||
hunk->HunkSetNext(mZone_HunkList);
|
||||
mZone_HunkList = hunk;
|
||||
++mZone_HunkCount;
|
||||
|
||||
morkRun* run = hunk->HunkRun();
|
||||
run->RunSetSize(inSize);
|
||||
#ifdef morkRun_USE_TAG_SLOT
|
||||
run->RunInitTag();
|
||||
#endif /* morkRun_USE_TAG_SLOT */
|
||||
|
||||
return hunk;
|
||||
}
|
||||
if ( ev->Good() ) // got this far without any error reported yet?
|
||||
ev->OutOfMemoryError();
|
||||
return (morkHunk*) 0;
|
||||
}
|
||||
|
||||
void* morkZone::zone_new_chip(morkEnv* ev, mdb_size inSize) // alloc
|
||||
{
|
||||
#ifdef morkZone_CONFIG_VOL_STATS
|
||||
mZone_BlockVolume += inSize; // sum sizes of both chips and runs
|
||||
#endif /* morkZone_CONFIG_VOL_STATS */
|
||||
|
||||
mork_u1* at = mZone_At;
|
||||
mork_size atSize = mZone_AtSize; // available bytes in current hunk
|
||||
if ( atSize >= inSize ) // current hunk can satisfy request?
|
||||
{
|
||||
mZone_At = at + inSize;
|
||||
mZone_AtSize = atSize - inSize;
|
||||
return at;
|
||||
}
|
||||
else if ( atSize > morkZone_kMaxHunkWaste ) // over max waste allowed?
|
||||
{
|
||||
morkHunk* hunk = this->zone_new_hunk(ev, inSize);
|
||||
if ( hunk )
|
||||
return hunk->HunkRun();
|
||||
|
||||
return (void*) 0; // show allocation has failed
|
||||
}
|
||||
else // get ourselves a new hunk for suballocation:
|
||||
{
|
||||
atSize = this->zone_grow_at(ev, inSize); // get a new hunk
|
||||
}
|
||||
|
||||
if ( atSize >= inSize ) // current hunk can satisfy request?
|
||||
{
|
||||
at = mZone_At;
|
||||
mZone_At = at + inSize;
|
||||
mZone_AtSize = atSize - inSize;
|
||||
return at;
|
||||
}
|
||||
|
||||
if ( ev->Good() ) // got this far without any error reported yet?
|
||||
ev->OutOfMemoryError();
|
||||
|
||||
return (void*) 0; // show allocation has failed
|
||||
}
|
||||
|
||||
void* morkZone::ZoneNewChip(morkEnv* ev, mdb_size inSize) // alloc
|
||||
{
|
||||
#ifdef morkZone_CONFIG_ARENA
|
||||
|
||||
#ifdef morkZone_CONFIG_DEBUG
|
||||
if ( !this->IsZone() )
|
||||
this->NonZoneTypeError(ev);
|
||||
else if ( !mZone_Heap )
|
||||
this->NilZoneHeapError(ev);
|
||||
#endif /*morkZone_CONFIG_DEBUG*/
|
||||
|
||||
#ifdef morkZone_CONFIG_ALIGN_8
|
||||
inSize += 7;
|
||||
inSize &= ~((mork_ip) 7); // force to multiple of 8 bytes
|
||||
#else /*morkZone_CONFIG_ALIGN_8*/
|
||||
inSize += 3;
|
||||
inSize &= ~((mork_ip) 3); // force to multiple of 4 bytes
|
||||
#endif /*morkZone_CONFIG_ALIGN_8*/
|
||||
|
||||
#ifdef morkZone_CONFIG_VOL_STATS
|
||||
mZone_ChipVolume += inSize; // sum sizes of chips only
|
||||
#endif /* morkZone_CONFIG_VOL_STATS */
|
||||
|
||||
return this->zone_new_chip(ev, inSize);
|
||||
|
||||
#else /*morkZone_CONFIG_ARENA*/
|
||||
void* outBlock = 0;
|
||||
mZone_Heap->Alloc(ev->AsMdbEnv(), inSize, &outBlock);
|
||||
return outBlock;
|
||||
#endif /*morkZone_CONFIG_ARENA*/
|
||||
|
||||
}
|
||||
|
||||
// public: // ...but runs do indeed know how big they are
|
||||
void* morkZone::ZoneNewRun(morkEnv* ev, mdb_size inSize) // alloc
|
||||
{
|
||||
#ifdef morkZone_CONFIG_ARENA
|
||||
|
||||
#ifdef morkZone_CONFIG_DEBUG
|
||||
if ( !this->IsZone() )
|
||||
this->NonZoneTypeError(ev);
|
||||
else if ( !mZone_Heap )
|
||||
this->NilZoneHeapError(ev);
|
||||
#endif /*morkZone_CONFIG_DEBUG*/
|
||||
|
||||
inSize += morkZone_kRoundAdd;
|
||||
inSize &= morkZone_kRoundMask;
|
||||
if ( inSize <= morkZone_kMaxCachedRun )
|
||||
{
|
||||
morkRun** bucket = mZone_FreeRuns + (inSize >> morkZone_kRoundBits);
|
||||
morkRun* hit = *bucket;
|
||||
if ( hit ) // cache hit?
|
||||
{
|
||||
*bucket = hit->RunNext();
|
||||
hit->RunSetSize(inSize);
|
||||
return hit->RunAsBlock();
|
||||
}
|
||||
}
|
||||
mdb_size blockSize = inSize + sizeof(morkRun); // plus run overhead
|
||||
#ifdef morkZone_CONFIG_VOL_STATS
|
||||
mZone_RunVolume += blockSize; // sum sizes of runs only
|
||||
#endif /* morkZone_CONFIG_VOL_STATS */
|
||||
morkRun* run = (morkRun*) this->zone_new_chip(ev, blockSize);
|
||||
if ( run )
|
||||
{
|
||||
run->RunSetSize(inSize);
|
||||
#ifdef morkRun_USE_TAG_SLOT
|
||||
run->RunInitTag();
|
||||
#endif /* morkRun_USE_TAG_SLOT */
|
||||
return run->RunAsBlock();
|
||||
}
|
||||
|
||||
if ( ev->Good() ) // got this far without any error reported yet?
|
||||
ev->OutOfMemoryError();
|
||||
|
||||
return (void*) 0; // indicate failed allocation
|
||||
|
||||
#else /*morkZone_CONFIG_ARENA*/
|
||||
void* outBlock = 0;
|
||||
mZone_Heap->Alloc(ev->AsMdbEnv(), inSize, &outBlock);
|
||||
return outBlock;
|
||||
#endif /*morkZone_CONFIG_ARENA*/
|
||||
}
|
||||
|
||||
void morkZone::ZoneZapRun(morkEnv* ev, void* ioRunBlock) // free
|
||||
{
|
||||
#ifdef morkZone_CONFIG_ARENA
|
||||
|
||||
morkRun* run = morkRun::BlockAsRun(ioRunBlock);
|
||||
mdb_size runSize = run->RunSize();
|
||||
#ifdef morkZone_CONFIG_VOL_STATS
|
||||
mZone_BlockVolume -= runSize; // tracking sizes of both chips and runs
|
||||
#endif /* morkZone_CONFIG_VOL_STATS */
|
||||
|
||||
#ifdef morkZone_CONFIG_DEBUG
|
||||
if ( !this->IsZone() )
|
||||
this->NonZoneTypeError(ev);
|
||||
else if ( !mZone_Heap )
|
||||
this->NilZoneHeapError(ev);
|
||||
else if ( !ioRunBlock )
|
||||
ev->NilPointerError();
|
||||
else if ( runSize & morkZone_kRoundAdd )
|
||||
run->RunSizeAlignError(ev);
|
||||
#ifdef morkRun_USE_TAG_SLOT
|
||||
else if ( !run->RunGoodTag() )
|
||||
run->BadRunTagError(ev);
|
||||
#endif /* morkRun_USE_TAG_SLOT */
|
||||
#endif /*morkZone_CONFIG_DEBUG*/
|
||||
|
||||
if ( runSize <= morkZone_kMaxCachedRun ) // goes into free run list?
|
||||
{
|
||||
morkRun** bucket = mZone_FreeRuns + (runSize >> morkZone_kRoundBits);
|
||||
run->RunSetNext(*bucket); // push onto free run list
|
||||
*bucket = run;
|
||||
}
|
||||
else // free old run list
|
||||
{
|
||||
run->RunSetNext(mZone_FreeOldRunList); // push onto free old run list
|
||||
mZone_FreeOldRunList = run;
|
||||
++mZone_FreeOldRunCount;
|
||||
#ifdef morkZone_CONFIG_VOL_STATS
|
||||
mZone_FreeOldRunVolume += runSize;
|
||||
#endif /* morkZone_CONFIG_VOL_STATS */
|
||||
|
||||
morkOldRun* oldRun = (morkOldRun*) run; // to access extra size slot
|
||||
oldRun->OldSetSize(runSize); // so we know how big this is later
|
||||
}
|
||||
|
||||
#else /*morkZone_CONFIG_ARENA*/
|
||||
mZone_Heap->Free(ev->AsMdbEnv(), ioRunBlock);
|
||||
#endif /*morkZone_CONFIG_ARENA*/
|
||||
}
|
||||
|
||||
void* morkZone::ZoneGrowRun(morkEnv* ev, void* ioRunBlock, mdb_size inSize)
|
||||
{
|
||||
#ifdef morkZone_CONFIG_ARENA
|
||||
|
||||
morkRun* run = morkRun::BlockAsRun(ioRunBlock);
|
||||
mdb_size runSize = run->RunSize();
|
||||
|
||||
#ifdef morkZone_CONFIG_DEBUG
|
||||
if ( !this->IsZone() )
|
||||
this->NonZoneTypeError(ev);
|
||||
else if ( !mZone_Heap )
|
||||
this->NilZoneHeapError(ev);
|
||||
#endif /*morkZone_CONFIG_DEBUG*/
|
||||
|
||||
#ifdef morkZone_CONFIG_ALIGN_8
|
||||
inSize += 7;
|
||||
inSize &= ~((mork_ip) 7); // force to multiple of 8 bytes
|
||||
#else /*morkZone_CONFIG_ALIGN_8*/
|
||||
inSize += 3;
|
||||
inSize &= ~((mork_ip) 3); // force to multiple of 4 bytes
|
||||
#endif /*morkZone_CONFIG_ALIGN_8*/
|
||||
|
||||
if ( inSize > runSize )
|
||||
{
|
||||
void* newBuf = this->ZoneNewRun(ev, inSize);
|
||||
if ( newBuf )
|
||||
{
|
||||
MORK_MEMCPY(newBuf, ioRunBlock, runSize);
|
||||
this->ZoneZapRun(ev, ioRunBlock);
|
||||
|
||||
return newBuf;
|
||||
}
|
||||
}
|
||||
else
|
||||
return ioRunBlock; // old size is big enough
|
||||
|
||||
if ( ev->Good() ) // got this far without any error reported yet?
|
||||
ev->OutOfMemoryError();
|
||||
|
||||
return (void*) 0; // indicate failed allocation
|
||||
|
||||
#else /*morkZone_CONFIG_ARENA*/
|
||||
void* outBlock = 0;
|
||||
mZone_Heap->Free(ev->AsMdbEnv(), ioRunBlock);
|
||||
return outBlock;
|
||||
#endif /*morkZone_CONFIG_ARENA*/
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// { ===== begin nsIMdbHeap methods =====
|
||||
/*virtual*/ mdb_err
|
||||
morkZone::Alloc(nsIMdbEnv* mev, // allocate a piece of memory
|
||||
mdb_size inSize, // requested size of new memory block
|
||||
void** outBlock) // memory block of inSize bytes, or nil
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
void* block = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
block = this->ZoneNewRun(ev, inSize);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
else
|
||||
outErr = 1;
|
||||
|
||||
if ( outBlock )
|
||||
*outBlock = block;
|
||||
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
morkZone::Free(nsIMdbEnv* mev, // free block allocated earlier by Alloc()
|
||||
void* inBlock)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
if ( inBlock )
|
||||
{
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
this->ZoneZapRun(ev, inBlock);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
else
|
||||
outErr = 1;
|
||||
}
|
||||
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
morkZone::HeapAddStrongRef(nsIMdbEnv* mev) // does nothing
|
||||
{
|
||||
MORK_USED_1(mev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
morkZone::HeapCutStrongRef(nsIMdbEnv* mev) // does nothing
|
||||
{
|
||||
MORK_USED_1(mev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// } ===== end nsIMdbHeap methods =====
|
||||
|
|
@ -0,0 +1,335 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MORKZONE_
|
||||
#define _MORKZONE_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKDEQUE_
|
||||
#include "morkDeque.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
/*| CONFIG_DEBUG: do paranoid debug checks if defined.
|
||||
|*/
|
||||
#ifdef MORK_DEBUG
|
||||
#define morkZone_CONFIG_DEBUG 1 /* debug paranoid if defined */
|
||||
#endif /*MORK_DEBUG*/
|
||||
|
||||
/*| CONFIG_STATS: keep volume and usage statistics.
|
||||
|*/
|
||||
#define morkZone_CONFIG_VOL_STATS 1 /* count space used by zone instance */
|
||||
|
||||
/*| CONFIG_ARENA: if this is defined, then the morkZone class will alloc big
|
||||
**| blocks from the zone's heap, and suballocate from these. If undefined,
|
||||
**| then morkZone will just pass all calls through to the zone's heap.
|
||||
|*/
|
||||
#ifdef MORK_ENABLE_ZONE_ARENAS
|
||||
#define morkZone_CONFIG_ARENA 1 /* be arena, if defined; otherwise no-op */
|
||||
#endif /*MORK_ENABLE_ZONE_ARENAS*/
|
||||
|
||||
/*| CONFIG_ALIGN_8: if this is defined, then the morkZone class will give
|
||||
**| blocks 8 byte alignment instead of only 4 byte alignment.
|
||||
|*/
|
||||
#ifdef MORK_CONFIG_ALIGN_8
|
||||
#define morkZone_CONFIG_ALIGN_8 1 /* ifdef: align to 8 bytes, otherwise 4 */
|
||||
#endif /*MORK_CONFIG_ALIGN_8*/
|
||||
|
||||
/*| CONFIG_PTR_SIZE_4: if this is defined, then the morkZone class will
|
||||
**| assume sizeof(void*) == 4, so a tag slot for padding is needed.
|
||||
|*/
|
||||
#ifdef MORK_CONFIG_PTR_SIZE_4
|
||||
#define morkZone_CONFIG_PTR_SIZE_4 1 /* ifdef: sizeof(void*) == 4 */
|
||||
#endif /*MORK_CONFIG_PTR_SIZE_4*/
|
||||
|
||||
/*| morkZone_USE_TAG_SLOT: if this is defined, then define slot mRun_Tag
|
||||
**| in order to achieve eight byte alignment after the mRun_Next slot.
|
||||
|*/
|
||||
#if defined(morkZone_CONFIG_ALIGN_8) && defined(morkZone_CONFIG_PTR_SIZE_4)
|
||||
#define morkRun_USE_TAG_SLOT 1 /* need mRun_Tag slot inside morkRun */
|
||||
#define morkHunk_USE_TAG_SLOT 1 /* need mHunk_Tag slot inside morkHunk */
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkRun_kTag ((mork_u4) 0x6D52754E ) /* ascii 'mRuN' */
|
||||
|
||||
/*| morkRun: structure used by morkZone for sized blocks
|
||||
|*/
|
||||
class morkRun {
|
||||
|
||||
protected: // member variable slots
|
||||
#ifdef morkRun_USE_TAG_SLOT
|
||||
mork_u4 mRun_Tag; // force 8 byte alignment after mRun_Next
|
||||
#endif /* morkRun_USE_TAG_SLOT */
|
||||
|
||||
morkRun* mRun_Next;
|
||||
|
||||
public: // pointer interpretation of mRun_Next (when inside a list):
|
||||
morkRun* RunNext() const { return mRun_Next; }
|
||||
void RunSetNext(morkRun* ioNext) { mRun_Next = ioNext; }
|
||||
|
||||
public: // size interpretation of mRun_Next (when not inside a list):
|
||||
mork_size RunSize() const { return (mork_size) ((mork_ip) mRun_Next); }
|
||||
void RunSetSize(mork_size inSize)
|
||||
{ mRun_Next = (morkRun*) ((mork_ip) inSize); }
|
||||
|
||||
public: // maintenance and testing of optional tag magic signature slot:
|
||||
#ifdef morkRun_USE_TAG_SLOT
|
||||
void RunInitTag() { mRun_Tag = morkRun_kTag; }
|
||||
mork_bool RunGoodTag() { return ( mRun_Tag == morkRun_kTag ); }
|
||||
#endif /* morkRun_USE_TAG_SLOT */
|
||||
|
||||
public: // conversion back and forth to inline block following run instance:
|
||||
void* RunAsBlock() { return (((mork_u1*) this) + sizeof(morkRun)); }
|
||||
|
||||
static morkRun* BlockAsRun(void* ioBlock)
|
||||
{ return (morkRun*) (((mork_u1*) ioBlock) - sizeof(morkRun)); }
|
||||
|
||||
public: // typing & errors
|
||||
static void BadRunTagError(morkEnv* ev);
|
||||
static void RunSizeAlignError(morkEnv* ev);
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
||||
/*| morkOldRun: more space to record size when run is put into old free list
|
||||
|*/
|
||||
class morkOldRun : public morkRun {
|
||||
|
||||
protected: // need another size field when mRun_Next is used for linkage:
|
||||
mdb_size mOldRun_Size;
|
||||
|
||||
public: // size getter/setter
|
||||
mork_size OldSize() const { return mOldRun_Size; }
|
||||
void OldSetSize(mork_size inSize) { mOldRun_Size = inSize; }
|
||||
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkHunk_kTag ((mork_u4) 0x68556E4B ) /* ascii 'hUnK' */
|
||||
|
||||
/*| morkHunk: structure used by morkZone for heap allocations.
|
||||
|*/
|
||||
class morkHunk {
|
||||
|
||||
protected: // member variable slots
|
||||
|
||||
#ifdef morkHunk_USE_TAG_SLOT
|
||||
mork_u4 mHunk_Tag; // force 8 byte alignment after mHunk_Next
|
||||
#endif /* morkHunk_USE_TAG_SLOT */
|
||||
|
||||
morkHunk* mHunk_Next;
|
||||
|
||||
morkRun mHunk_Run;
|
||||
|
||||
public: // setters
|
||||
void HunkSetNext(morkHunk* ioNext) { mHunk_Next = ioNext; }
|
||||
|
||||
public: // getters
|
||||
morkHunk* HunkNext() const { return mHunk_Next; }
|
||||
|
||||
morkRun* HunkRun() { return &mHunk_Run; }
|
||||
|
||||
public: // maintenance and testing of optional tag magic signature slot:
|
||||
#ifdef morkHunk_USE_TAG_SLOT
|
||||
void HunkInitTag() { mHunk_Tag = morkHunk_kTag; }
|
||||
mork_bool HunkGoodTag() { return ( mHunk_Tag == morkHunk_kTag ); }
|
||||
#endif /* morkHunk_USE_TAG_SLOT */
|
||||
|
||||
public: // typing & errors
|
||||
static void BadHunkTagWarning(morkEnv* ev);
|
||||
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
/*| kNewHunkSize: the default size for a hunk, assuming we must allocate
|
||||
**| a new one whenever the free hunk list does not already have. Note this
|
||||
**| number should not be changed without also considering suitable changes
|
||||
**| in the related kMaxHunkWaste and kMinHunkSize constants.
|
||||
|*/
|
||||
#define morkZone_kNewHunkSize ((mork_size) (64 * 1024)) /* 64K per hunk */
|
||||
|
||||
/*| kMaxFreeVolume: some number of bytes of free space in the free hunk list
|
||||
**| over which we no longer want to add more free hunks to the list, for fear
|
||||
**| of accumulating too much unused, fragmented free space. This should be a
|
||||
**| small multiple of kNewHunkSize, say about two to four times as great, to
|
||||
**| allow for no more free hunk space than fits in a handful of new hunks.
|
||||
**| This strategy will let us usefully accumulate "some" free space in the
|
||||
**| free hunk list, but without accumulating "too much" free space that way.
|
||||
|*/
|
||||
#define morkZone_kMaxFreeVolume (morkZone_kNewHunkSize * 3)
|
||||
|
||||
/*| kMaxHunkWaste: if a current request is larger than this, and we cannot
|
||||
**| satisfy the request with the current hunk, then we just allocate the
|
||||
**| block from the heap without changing the current hunk. Basically this
|
||||
**| number represents the largest amount of memory we are willing to waste,
|
||||
**| since a block request barely less than this can cause the current hunk
|
||||
**| to be retired (with any unused space wasted) as well get a new hunk.
|
||||
|*/
|
||||
#define morkZone_kMaxHunkWaste ((mork_size) 4096) /* 1/16 kNewHunkSize */
|
||||
|
||||
/*| kRound*: the algorithm for rounding up allocation sizes for caching
|
||||
**| in free lists works like the following. We add kRoundAdd to any size
|
||||
**| requested, and then bitwise AND with kRoundMask, and this will give us
|
||||
**| the smallest multiple of kRoundSize that is at least as large as the
|
||||
**| requested size. Then if we rightshift this number by kRoundBits, we
|
||||
**| will have the index into the mZone_FreeRuns array which will hold any
|
||||
**| cache runs of that size. So 4 bits of shift gives us a granularity
|
||||
**| of 16 bytes, so that free lists will hold successive runs that are
|
||||
**| 16 bytes greater than the next smaller run size. If we have 256 free
|
||||
**| lists of nonzero sized runs altogether, then the largest run that can
|
||||
**| be cached is 4096, or 4K (since 4096 == 16 * 256). A larger run that
|
||||
**| gets freed will go in to the free hunk list (or back to the heap).
|
||||
|*/
|
||||
#define morkZone_kRoundBits 4 /* bits to round-up size for free lists */
|
||||
#define morkZone_kRoundSize (1 << morkZone_kRoundBits)
|
||||
#define morkZone_kRoundAdd ((1 << morkZone_kRoundBits) - 1)
|
||||
#define morkZone_kRoundMask (~ ((mork_ip) morkZone_kRoundAdd))
|
||||
|
||||
#define morkZone_kBuckets 256 /* number of distinct free lists */
|
||||
|
||||
/*| kMaxCachedRun: the largest run that will be stored inside a free
|
||||
**| list of old zapped runs. A run larger than this cannot be put in
|
||||
**| a free list, and must be allocated from the heap at need, and put
|
||||
**| into the free hunk list when discarded.
|
||||
|*/
|
||||
#define morkZone_kMaxCachedRun (morkZone_kBuckets * morkZone_kRoundSize)
|
||||
|
||||
#define morkDerived_kZone /*i*/ 0x5A6E /* ascii 'Zn' */
|
||||
|
||||
/*| morkZone: a pooled memory allocator like an NSPR arena. The term 'zone'
|
||||
**| is roughly synonymous with 'heap'. I avoid calling this class a "heap"
|
||||
**| to avoid any confusion with nsIMdbHeap, and I avoid calling this class
|
||||
**| an arean to avoid confusion with NSPR usage.
|
||||
|*/
|
||||
class morkZone : public morkNode, public nsIMdbHeap {
|
||||
|
||||
// public: // slots inherited from morkNode (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
|
||||
// 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
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
nsIMdbHeap* mZone_Heap; // strong ref to heap allocating all space
|
||||
|
||||
mork_size mZone_HeapVolume; // total bytes allocated from heap
|
||||
mork_size mZone_BlockVolume; // total bytes in all zone blocks
|
||||
mork_size mZone_RunVolume; // total bytes in all zone runs
|
||||
mork_size mZone_ChipVolume; // total bytes in all zone chips
|
||||
|
||||
mork_size mZone_FreeOldRunVolume; // total bytes in all used hunks
|
||||
|
||||
mork_count mZone_HunkCount; // total number of used hunks
|
||||
mork_count mZone_FreeOldRunCount; // total free old runs
|
||||
|
||||
morkHunk* mZone_HunkList; // linked list of all used hunks
|
||||
morkRun* mZone_FreeOldRunList; // linked list of free old runs
|
||||
|
||||
// note mZone_At is a byte pointer for single byte address arithmetic:
|
||||
mork_u1* mZone_At; // current position in most recent hunk
|
||||
mork_size mZone_AtSize; // number of bytes remaining in this hunk
|
||||
|
||||
// kBuckets+1 so indexes zero through kBuckets are all okay to use:
|
||||
|
||||
morkRun* mZone_FreeRuns[ morkZone_kBuckets + 1 ];
|
||||
// Each piece of memory stored in list mZone_FreeRuns[ i ] has an
|
||||
// allocation size equal to sizeof(morkRun) + (i * kRoundSize), so
|
||||
// that callers can be given a piece of memory with (i * kRoundSize)
|
||||
// bytes of writeable space while reserving the first sizeof(morkRun)
|
||||
// bytes to keep track of size information for later re-use. Note
|
||||
// that mZone_FreeRuns[ 0 ] is unused because no run will be zero
|
||||
// bytes in size (and morkZone plans to complain about zero sizes).
|
||||
|
||||
protected: // zone utilities
|
||||
|
||||
mork_size zone_grow_at(morkEnv* ev, mork_size inNeededSize);
|
||||
|
||||
void* zone_new_chip(morkEnv* ev, mdb_size inSize); // alloc
|
||||
morkHunk* zone_new_hunk(morkEnv* ev, mdb_size inRunSize); // alloc
|
||||
|
||||
// { ===== begin nsIMdbHeap methods =====
|
||||
public:
|
||||
virtual mdb_err Alloc(nsIMdbEnv* ev, // allocate a piece of memory
|
||||
mdb_size inSize, // requested size of new memory block
|
||||
void** outBlock); // memory block of inSize bytes, or nil
|
||||
|
||||
virtual mdb_err Free(nsIMdbEnv* ev, // free block allocated earlier by Alloc()
|
||||
void* inBlock);
|
||||
|
||||
virtual mdb_err HeapAddStrongRef(nsIMdbEnv* ev); // does nothing
|
||||
virtual mdb_err HeapCutStrongRef(nsIMdbEnv* ev); // does nothing
|
||||
// } ===== end nsIMdbHeap methods =====
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseZone() only if open
|
||||
virtual ~morkZone(); // assert that CloseMap() executed earlier
|
||||
|
||||
public: // morkMap construction & destruction
|
||||
morkZone(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioNodeHeap,
|
||||
nsIMdbHeap* ioZoneHeap);
|
||||
|
||||
void CloseZone(morkEnv* ev); // called by CloseMorkNode()
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsZone() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kZone; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
// { ===== begin morkZone methods =====
|
||||
public: // chips do not know how big they are...
|
||||
void* ZoneNewChip(morkEnv* ev, mdb_size inSize); // alloc
|
||||
|
||||
public: // ...but runs do indeed know how big they are
|
||||
void* ZoneNewRun(morkEnv* ev, mdb_size inSize); // alloc
|
||||
void ZoneZapRun(morkEnv* ev, void* ioRunBody); // free
|
||||
void* ZoneGrowRun(morkEnv* ev, void* ioRunBody, mdb_size inSize); // realloc
|
||||
|
||||
// } ===== end morkZone methods =====
|
||||
|
||||
public: // typing & errors
|
||||
static void NonZoneTypeError(morkEnv* ev);
|
||||
static void NilZoneHeapError(morkEnv* ev);
|
||||
static void BadZoneTagError(morkEnv* ev);
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKZONE_ */
|
Загрузка…
Ссылка в новой задаче