Back to index

lightning-sunbird  0.9+nobinonly
morkProbeMap.h
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-  */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 // This code is a port to NS Mork from public domain Mithril C++ sources.
00039 // Note many code comments here come verbatim from cut-and-pasted Mithril.
00040 // In many places, code is identical; Mithril versions stay public domain.
00041 // Changes in porting are mainly class type and scalar type name changes.
00042 
00043 #ifndef _MORKPROBEMAP_
00044 #define _MORKPROBEMAP_ 1
00045 
00046 #ifndef _MORK_
00047 #include "mork.h"
00048 #endif
00049 
00050 #ifndef _MORKNODE_
00051 #include "morkNode.h"
00052 #endif
00053 
00054 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00055 
00056 class morkMapScratch { // utility class used by map subclasses
00057 public:
00058   nsIMdbHeap*  sMapScratch_Heap;     // cached sMap_Heap
00059   mork_count   sMapScratch_Slots;    // cached sMap_Slots
00060   
00061   mork_u1*     sMapScratch_Keys;     // cached sMap_Keys
00062   mork_u1*     sMapScratch_Vals;     // cached sMap_Vals
00063   
00064 public:
00065   void halt_map_scratch(morkEnv* ev);
00066 };
00067 
00068 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00069 
00070 #define morkDerived_kProbeMap   0x7072 /* ascii 'pr' */
00071 #define morkProbeMap_kTag     0x70724D50 /* ascii 'prMP' */
00072 
00073 #define morkProbeMap_kLazyClearOnAdd ((mork_u1) 'c')
00074  
00075 class morkProbeMap: public morkNode {
00076 
00077 protected:
00078 
00079 // public: // slots inherited from morkNode (meant to inform only)
00080   // nsIMdbHeap*       mNode_Heap;
00081 
00082   // mork_base      mNode_Base;     // must equal morkBase_kNode
00083   // mork_derived   mNode_Derived;  // depends on specific node subclass
00084   
00085   // mork_access    mNode_Access;   // kOpen, kClosing, kShut, or kDead
00086   // mork_usage     mNode_Usage;    // kHeap, kStack, kMember, kGlobal, kNone
00087   // mork_able      mNode_Mutable;  // can this node be modified?
00088   // mork_load      mNode_Load;     // is this node clean or dirty?
00089   
00090   // mork_uses      mNode_Uses;     // refcount for strong refs
00091   // mork_refs      mNode_Refs;     // refcount for strong refs + weak refs
00092 
00093 protected:
00094   // { begin morkMap slots
00095   nsIMdbHeap* sMap_Heap; // strong ref to heap allocating all space
00096     
00097   mork_u1*    sMap_Keys;
00098   mork_u1*    sMap_Vals;
00099   
00100   mork_count  sMap_Seed;   // change count of members or structure
00101     
00102   mork_count  sMap_Slots;  // count of slots in the hash table
00103   mork_fill   sMap_Fill;   // number of used slots in the hash table
00104 
00105   mork_size   sMap_KeySize; // size of each key (cannot be zero)
00106   mork_size   sMap_ValSize; // size of each val (zero allowed)
00107   
00108   mork_bool   sMap_KeyIsIP;     // sMap_KeySize == sizeof(mork_ip)
00109   mork_bool   sMap_ValIsIP;     // sMap_ValSize == sizeof(mork_ip)
00110   mork_u1     sMap_Pad[ 2 ];    // for u4 alignment
00111   // } end morkMap slots
00112     
00113   friend class morkProbeMapIter; // for access to protected slots
00114 
00115 public: // getters
00116   mork_count  MapSeed() const { return sMap_Seed; }
00117     
00118   mork_count  MapSlots() const { return sMap_Slots; }
00119   mork_fill   MapFill() const { return sMap_Fill; }
00120 
00121   mork_size   MapKeySize() const { return sMap_KeySize; }
00122   mork_size   MapValSize() const { return sMap_ValSize; }
00123   
00124   mork_bool   MapKeyIsIP() const { return sMap_KeyIsIP; }
00125   mork_bool   MapValIsIP() const { return sMap_ValIsIP; }
00126 
00127 protected: // slots
00128   // { begin morkProbeMap slots
00129    
00130   mork_fill   sProbeMap_MaxFill; // max sMap_Fill before map must grow
00131   
00132   mork_u1     sProbeMap_LazyClearOnAdd; // true if kLazyClearOnAdd
00133   mork_bool   sProbeMap_ZeroIsClearKey; // zero is adequate to clear keys
00134   mork_u1     sProbeMap_Pad[ 2 ]; // for u4 alignment
00135   
00136   mork_u4     sProbeMap_Tag; 
00137  
00138   // } end morkProbeMap slots
00139     
00140 public: // lazy clear on add
00141 
00142   mork_bool need_lazy_init() const 
00143   { return sProbeMap_LazyClearOnAdd == morkProbeMap_kLazyClearOnAdd; }
00144 
00145 public: // typing
00146   mork_bool   GoodProbeMap() const
00147   { return sProbeMap_Tag == morkProbeMap_kTag; }
00148     
00149 protected: // utilities
00150 
00151   void* clear_alloc(morkEnv* ev, mork_size inSize);
00152 
00153   mork_u1*    map_new_vals(morkEnv* ev, mork_num inSlots);
00154   mork_u1*    map_new_keys(morkEnv* ev, mork_num inSlots);
00155 
00156   void clear_probe_map(morkEnv* ev, nsIMdbHeap* ioMapHeap);
00157   void init_probe_map(morkEnv* ev, mork_size inSlots);
00158   void probe_map_lazy_init(morkEnv* ev);
00159 
00160   mork_bool new_slots(morkEnv* ev, morkMapScratch* old, mork_num inSlots);
00161   
00162   mork_test find_key_pos(morkEnv* ev, const void* inAppKey,
00163     mork_u4 inHash, mork_pos* outPos) const;
00164   
00165   void put_probe_kv(morkEnv* ev,
00166     const void* inAppKey, const void* inAppVal, mork_pos inPos);
00167   void get_probe_kv(morkEnv* ev,
00168     void* outAppKey, void* outAppVal, mork_pos inPos) const;
00169     
00170   mork_bool grow_probe_map(morkEnv* ev);
00171   void      rehash_old_map(morkEnv* ev, morkMapScratch* ioScratch);
00172   void      revert_map(morkEnv* ev, morkMapScratch* ioScratch);
00173 
00174 public: // errors
00175   void ProbeMapBadTagError(morkEnv* ev) const;
00176   void WrapWithNoVoidSlotError(morkEnv* ev) const;
00177   void GrowFailsMaxFillError(morkEnv* ev) const;
00178   void MapKeyIsNotIPError(morkEnv* ev) const;
00179   void MapValIsNotIPError(morkEnv* ev) const;
00180 
00181   void MapNilKeysError(morkEnv* ev);
00182   void MapZeroKeySizeError(morkEnv* ev);
00183 
00184   void MapSeedOutOfSyncError(morkEnv* ev);
00185   void MapFillUnderflowWarning(morkEnv* ev);
00186 
00187   static void ProbeMapCutError(morkEnv* ev);
00188 
00189   // { ===== begin morkMap methods =====
00190 public:
00191 
00192   virtual mork_test // hit(a,b) implies hash(a) == hash(b)
00193   MapTest(morkEnv* ev, const void* inMapKey, const void* inAppKey) const;
00194     // Note inMapKey is always a key already stored in the map, while inAppKey
00195     //   is always a method argument parameter from a client method call.
00196     //   This matters the most in morkProbeMap subclasses, which have the
00197     //   responsibility of putting 'app' keys into slots for 'map' keys, and
00198     //   the bit pattern representation might be different in such cases.
00199     // morkTest_kHit means that inMapKey equals inAppKey (and this had better
00200     //   also imply that hash(inMapKey) == hash(inAppKey)).
00201     // morkTest_kMiss means that inMapKey does NOT equal inAppKey (but this
00202     //   implies nothing at all about hash(inMapKey) and hash(inAppKey)).
00203     // morkTest_kVoid means that inMapKey is not a valid key bit pattern,
00204     //   which means that key slot in the map is not being used.  Note that
00205     //   kVoid is only expected as a return value in morkProbeMap subclasses,
00206     //   because morkProbeMap must ask whether a key slot is used or not. 
00207     //   morkChainMap however, always knows when a key slot is used, so only
00208     //   key slots expected to have valid bit patterns will be presented to
00209     //   the MapTest() methods for morkChainMap subclasses.
00210     //
00211     // NOTE: it is very important that subclasses correctly return the value
00212     // morkTest_kVoid whenever the slot for inMapKey contains a bit pattern
00213     // that means the slot is not being used, because this is the only way a
00214     // probe map can terminate an unsuccessful search for a key in the map.
00215 
00216   virtual mork_u4 // hit(a,b) implies hash(a) == hash(b)
00217   MapHash(morkEnv* ev, const void* inAppKey) const;
00218 
00219   virtual mork_bool
00220   MapAtPut(morkEnv* ev, const void* inAppKey, const void* inAppVal,
00221     void* outAppKey, void* outAppVal);
00222     
00223   virtual mork_bool
00224   MapAt(morkEnv* ev, const void* inAppKey, void* outAppKey, void* outAppVal);
00225     
00226   virtual mork_num
00227   MapCutAll(morkEnv* ev);
00228   // } ===== end morkMap methods =====
00229 
00230     
00231   // { ===== begin morkProbeMap methods =====
00232 public:
00233 
00234   virtual mork_u4
00235   ProbeMapHashMapKey(morkEnv* ev, const void* inMapKey) const;
00236     // ProbeMapHashMapKey() does logically the same thing as MapHash(), and
00237     // the default implementation actually calls virtual MapHash().  However,
00238     // Subclasses must override this method whenever the formats of keys in
00239     // the map differ from app keys outside the map, because MapHash() only
00240     // works on keys in 'app' format, while ProbeMapHashMapKey() only works
00241     // on keys in 'map' format.  This method is called in order to rehash all
00242     // map keys when a map is grown, and this causes all old map members to
00243     // move into new slot locations.
00244     //
00245     // Note it is absolutely imperative that a hash for a key in 'map' format
00246     // be exactly the same the hash of the same key in 'app' format, or else
00247     // maps will seem corrupt later when keys in 'app' format cannot be found.
00248 
00249   virtual mork_bool
00250   ProbeMapIsKeyNil(morkEnv* ev, void* ioMapKey);
00251     // ProbeMapIsKeyNil() must say whether the representation of logical 'nil'
00252     // is currently found inside the key at ioMapKey, for a key found within
00253     // the map.  The the map iterator uses this method to find map keys that
00254     // are actually being used for valid map associations; otherwise the
00255     // iterator cannot determine which map slots actually denote used keys.
00256     // The default method version returns true if all the bits equal zero.
00257 
00258   virtual void
00259   ProbeMapClearKey(morkEnv* ev, // put 'nil' alls keys inside map
00260     void* ioMapKey, mork_count inKeyCount); // array of keys inside map
00261     // ProbeMapClearKey() must put some representation of logical 'nil' into
00262     // every key slot in the map, such that MapTest() will later recognize
00263     // that this bit pattern shows each key slot is not actually being used.
00264     //
00265     // This method is typically called whenever the map is either created or
00266     // grown into a larger size, where ioMapKey is a pointer to an array of
00267     // inKeyCount keys, where each key is this->MapKeySize() bytes in size.
00268     // Note that keys are assumed immediately adjacent with no padding, so
00269     // if any alignment requirements must be met, then subclasses should have
00270     // already accounted for this when specifying a key size in the map.
00271     //
00272     // Since this method will be called when a map is being grown in size,
00273     // nothing should be assumed about the state slots of the map, since the
00274     // ioMapKey array might not yet live in sMap_Keys, and the array length
00275     // inKeyCount might not yet live in sMap_Slots.  However, the value kept
00276     // in sMap_KeySize never changes, so this->MapKeySize() is always correct.
00277 
00278   virtual void
00279   ProbeMapPushIn(morkEnv* ev, // move (key,val) into the map
00280     const void* inAppKey, const void* inAppVal, // (key,val) outside map
00281     void* outMapKey, void* outMapVal);      // (key,val) inside map
00282     // This method actually puts keys and vals in the map in suitable format.
00283     //
00284     // ProbeMapPushIn() must copy a caller key and value in 'app' format
00285     // into the map slots provided, which are in 'map' format.  When the
00286     // 'app' and 'map' formats are identical, then this is just a bitwise
00287     // copy of this->MapKeySize() key bytes and this->MapValSize() val bytes,
00288     // and this is exactly what the default implementation performs.  However,
00289     // if 'app' and 'map' formats are different, and MapTest() depends on this
00290     // difference in format, then subclasses must override this method to do
00291     // whatever is necessary to store the input app key in output map format.
00292     //
00293     // Do NOT write more than this->MapKeySize() bytes of a map key, or more
00294     // than this->MapValSize() bytes of a map val, or corruption might ensue.
00295     //
00296     // The inAppKey and inAppVal parameters are the same ones passed into a
00297     // call to MapAtPut(), and the outMapKey and outMapVal parameters are ones
00298     // determined by how the map currently positions key inAppKey in the map.
00299     //
00300     // Note any key or val parameter can be a null pointer, in which case
00301     // this method must do nothing with those parameters.  In particular, do
00302     // no key move at all when either inAppKey or outMapKey is nil, and do
00303     // no val move at all when either inAppVal or outMapVal is nil.  Note that
00304     // outMapVal should always be nil when this->MapValSize() is nil.
00305 
00306   virtual void
00307   ProbeMapPullOut(morkEnv* ev, // move (key,val) out from the map
00308     const void* inMapKey, const void* inMapVal, // (key,val) inside map
00309     void* outAppKey, void* outAppVal) const;    // (key,val) outside map
00310     // This method actually gets keys and vals from the map in suitable format.
00311     //
00312     // ProbeMapPullOut() must copy a key and val in 'map' format into the
00313     // caller key and val slots provided, which are in 'app' format.  When the
00314     // 'app' and 'map' formats are identical, then this is just a bitwise
00315     // copy of this->MapKeySize() key bytes and this->MapValSize() val bytes,
00316     // and this is exactly what the default implementation performs.  However,
00317     // if 'app' and 'map' formats are different, and MapTest() depends on this
00318     // difference in format, then subclasses must override this method to do
00319     // whatever is necessary to store the input map key in output app format.
00320     //
00321     // The outAppKey and outAppVal parameters are the same ones passed into a
00322     // call to either MapAtPut() or MapAt(), while inMapKey and inMapVal are
00323     // determined by how the map currently positions the target key in the map.
00324     //
00325     // Note any key or val parameter can be a null pointer, in which case
00326     // this method must do nothing with those parameters.  In particular, do
00327     // no key move at all when either inMapKey or outAppKey is nil, and do
00328     // no val move at all when either inMapVal or outAppVal is nil.  Note that
00329     // inMapVal should always be nil when this->MapValSize() is nil.
00330   
00331   // } ===== end morkProbeMap methods =====
00332     
00333   
00334 // { ===== begin morkNode interface =====
00335 public: // morkNode virtual methods
00336   virtual void CloseMorkNode(morkEnv* ev); // CloseProbeMap() only if open
00337   virtual ~morkProbeMap(); // assert that CloseProbeMap() executed earlier
00338   
00339 public: // morkProbeMap construction & destruction
00340   morkProbeMap(morkEnv* ev, const morkUsage& inUsage,
00341   nsIMdbHeap* ioNodeHeap,
00342   mork_size inKeySize, mork_size inValSize,
00343   nsIMdbHeap* ioMapHeap, mork_size inSlots,
00344   mork_bool inZeroIsClearKey);
00345   
00346   void CloseProbeMap(morkEnv* ev); // called by 
00347   
00348 public: // dynamic type identification
00349   mork_bool IsProbeMap() const
00350   { return IsNode() && mNode_Derived == morkDerived_kProbeMap; }
00351 // } ===== end morkNode methods =====
00352 
00353 public: // typesafe refcounting inlines calling inherited morkNode methods
00354   static void SlotWeakMap(morkMap* me,
00355     morkEnv* ev, morkMap** ioSlot)
00356   { morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
00357   
00358   static void SlotStrongMap(morkMap* me,
00359     morkEnv* ev, morkMap** ioSlot)
00360   { morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
00361 };
00362 
00363 /*============================================================================*/
00364 /* morkProbeMapIter */
00365 
00366 #define morkProbeMapIter_kBeforeIx ((mork_i4) -1) /* before first member */
00367 #define morkProbeMapIter_kAfterIx  ((mork_i4) -2) /* after last member */
00368 
00369 class morkProbeMapIter {
00370 
00371 protected:
00372   morkProbeMap* sProbeMapIter_Map;      // nonref
00373   mork_num      sProbeMapIter_Seed;     // iter's cached copy of map's seed
00374   
00375   mork_i4       sProbeMapIter_HereIx;
00376   
00377   mork_change   sProbeMapIter_Change;   // morkMapIter API simulation dummy
00378   mork_u1       sProbeMapIter_Pad[ 3 ]; // for u4 alignment
00379   
00380 public:
00381   morkProbeMapIter(morkEnv* ev, morkProbeMap* ioMap);
00382   void CloseMapIter(morkEnv* ev);
00383  
00384   morkProbeMapIter( ); // zero most slots; caller must call InitProbeMapIter()
00385 
00386 protected: // protected so subclasses must provide suitable typesafe inlines:
00387 
00388   void InitProbeMapIter(morkEnv* ev, morkProbeMap* ioMap);
00389    
00390   void InitMapIter(morkEnv* ev, morkProbeMap* ioMap) // morkMapIter compatibility
00391   { this->InitProbeMapIter(ev, ioMap); }
00392    
00393   mork_bool IterFirst(morkEnv* ev, void* outKey, void* outVal);
00394   mork_bool IterNext(morkEnv* ev, void* outKey, void* outVal);
00395   mork_bool IterHere(morkEnv* ev, void* outKey, void* outVal);
00396    
00397   // NOTE: the following methods ONLY work for sMap_ValIsIP pointer values.
00398   // (Note the implied assumption that zero is never a good value pattern.)
00399   
00400   void*     IterFirstVal(morkEnv* ev, void* outKey);
00401   // equivalent to { void* v=0; this->IterFirst(ev, outKey, &v); return v; }
00402   
00403   void*     IterNextVal(morkEnv* ev, void* outKey);
00404   // equivalent to { void* v=0; this->IterNext(ev, outKey, &v); return v; }
00405 
00406   void*     IterHereVal(morkEnv* ev, void* outKey);
00407   // equivalent to { void* v=0; this->IterHere(ev, outKey, &v); return v; }
00408 
00409   // NOTE: the following methods ONLY work for sMap_KeyIsIP pointer values.
00410   // (Note the implied assumption that zero is never a good key pattern.)
00411   
00412   void*     IterFirstKey(morkEnv* ev);
00413   // equivalent to { void* k=0; this->IterFirst(ev, &k, 0); return k; }
00414   
00415   void*     IterNextKey(morkEnv* ev);
00416   // equivalent to { void* k=0; this->IterNext(ev, &k, 0); return k; }
00417 
00418   void*     IterHereKey(morkEnv* ev);
00419   // equivalent to { void* k=0; this->IterHere(ev, &k, 0); return k; }
00420 
00421 public: // simulation of the morkMapIter API for morkMap compatibility:  
00422   mork_change* First(morkEnv* ev, void* outKey, void* outVal);
00423   mork_change* Next(morkEnv* ev, void* outKey, void* outVal);
00424   mork_change* Here(morkEnv* ev, void* outKey, void* outVal);
00425   
00426   mork_change* CutHere(morkEnv* ev, void* outKey, void* outVal);
00427 };
00428 
00429 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00430 
00431 #endif /* _MORKPROBEMAP_ */