/* -*- 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 ***** */ // 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 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) override; // 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_ */