Back to index

lightning-sunbird  0.9+nobinonly
morkProbeMap.cpp
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 #include "nscore.h"
00044 
00045 #ifndef _MDB_
00046 #include "mdb.h"
00047 #endif
00048 
00049 #ifndef _MORK_
00050 #include "mork.h"
00051 #endif
00052 
00053 #ifndef _MORKNODE_
00054 #include "morkNode.h"
00055 #endif
00056 
00057 #ifndef _MORKPROBEMAP_
00058 #include "morkProbeMap.h"
00059 #endif
00060 
00061 #ifndef _MORKENV_
00062 #include "morkEnv.h"
00063 #endif
00064 
00065 /*============================================================================*/
00066 /* morkMapScratch */
00067 
00068 void morkMapScratch::halt_map_scratch(morkEnv* ev)
00069 {
00070   nsIMdbHeap* heap = sMapScratch_Heap;
00071   
00072   if ( heap )
00073   {
00074     if ( sMapScratch_Keys )
00075       heap->Free(ev->AsMdbEnv(), sMapScratch_Keys);
00076     if ( sMapScratch_Vals )
00077       heap->Free(ev->AsMdbEnv(), sMapScratch_Vals);
00078   }
00079 }
00080 
00081 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00082 
00083 
00084 /*============================================================================*/
00085 /* morkProbeMap */
00086 
00087 void morkProbeMap::ProbeMapBadTagError(morkEnv* ev) const
00088 {
00089   ev->NewError("bad sProbeMap_Tag");
00090   if ( !this )
00091     ev->NewError("nil morkProbeMap");
00092 }
00093 
00094 void morkProbeMap::WrapWithNoVoidSlotError(morkEnv* ev) const
00095 {
00096   ev->NewError("wrap without void morkProbeMap slot");
00097 }
00098 
00099 void morkProbeMap::GrowFailsMaxFillError(morkEnv* ev) const
00100 {
00101   ev->NewError("grow fails morkEnv > sMap_Fill");
00102 }
00103 
00104 void morkProbeMap::MapKeyIsNotIPError(morkEnv* ev) const
00105 {
00106   ev->NewError("not sMap_KeyIsIP");
00107 }
00108 
00109 void morkProbeMap::MapValIsNotIPError(morkEnv* ev) const
00110 {
00111   ev->NewError("not sMap_ValIsIP");
00112 }
00113 
00114 void morkProbeMap::rehash_old_map(morkEnv* ev, morkMapScratch* ioScratch)
00115 {
00116   mork_size keySize = sMap_KeySize; // size of every key bucket
00117   mork_size valSize = sMap_ValSize; // size of every associated value
00118   
00119   mork_count slots = sMap_Slots; // number of new buckets
00120   mork_u1* keys = sMap_Keys; // destination for rehashed keys
00121   mork_u1* vals = sMap_Vals; // destination for any copied values
00122   
00123   mork_bool keyIsIP = ( keys && keySize == sizeof(mork_ip) && sMap_KeyIsIP );
00124   mork_bool valIsIP = ( vals && valSize == sizeof(mork_ip) && sMap_ValIsIP );
00125 
00126   mork_count oldSlots = ioScratch->sMapScratch_Slots; // sMap_Slots
00127   mork_u1* oldKeys = ioScratch->sMapScratch_Keys; // sMap_Keys
00128   mork_u1* oldVals = ioScratch->sMapScratch_Vals; // sMap_Vals
00129   mork_u1* end = oldKeys + (keySize * oldSlots); // one byte past last key
00130   
00131   mork_fill fill = 0; // let's count the actual fill for a double check
00132   
00133   while ( oldKeys < end ) // another old key bucket to rehash if non-nil?
00134   {
00135     if ( !this->ProbeMapIsKeyNil(ev, oldKeys) ) // need to rehash?
00136     {
00137       ++fill; // this had better match sMap_Fill when we are all done
00138       mork_u4 hash = this->ProbeMapHashMapKey(ev, oldKeys);
00139 
00140       mork_pos i = hash % slots;   // target hash bucket
00141       mork_pos startPos = i;       // remember start to detect
00142       
00143       mork_u1* k = keys + (i * keySize);
00144       while ( !this->ProbeMapIsKeyNil(ev, k) )
00145       {
00146         if ( ++i >= (mork_pos)slots ) // advanced past end? need to wrap around now?
00147           i = 0; // wrap around to first slot in map's hash table
00148           
00149         if ( i == startPos ) // no void slots were found anywhere in map?
00150         {
00151           this->WrapWithNoVoidSlotError(ev); // should never happen
00152           return; // this is bad, and we can't go on with the rehash
00153         }
00154         k = keys + (i * keySize);
00155       }
00156       if ( keyIsIP ) // int special case?
00157         *((mork_ip*) k) = *((const mork_ip*) oldKeys); // fast bitwise copy
00158       else
00159         MORK_MEMCPY(k, oldKeys, keySize); // slow bitwise copy
00160 
00161       if ( oldVals ) // need to copy values as well?
00162       {
00163         mork_size valOffset = (i * valSize);
00164         mork_u1* v = vals + valOffset;
00165         mork_u1* ov = oldVals + valOffset;
00166         if ( valIsIP ) // int special case?
00167           *((mork_ip*) v) = *((const mork_ip*) ov); // fast bitwise copy
00168         else
00169           MORK_MEMCPY(v, ov, valSize); // slow bitwise copy
00170       }
00171     }
00172     oldKeys += keySize; // advance to next key bucket in old map
00173   }
00174   if ( fill != sMap_Fill ) // is the recorded value of sMap_Fill wrong?
00175   {
00176     ev->NewWarning("fill != sMap_Fill");
00177     sMap_Fill = fill;
00178   }
00179 }
00180 
00181 mork_bool morkProbeMap::grow_probe_map(morkEnv* ev)
00182 {
00183   if ( sMap_Heap ) // can we grow the map?
00184   {
00185     mork_num newSlots = ((sMap_Slots * 4) / 3) + 1; // +25%
00186     morkMapScratch old; // a place to temporarily hold all the old arrays
00187     if ( this->new_slots(ev, &old, newSlots) ) // have more?
00188     {      
00189       ++sMap_Seed; // note the map has changed
00190       this->rehash_old_map(ev, &old);
00191       
00192       if ( ev->Good() ) 
00193       {
00194         mork_count slots = sMap_Slots;
00195         mork_num emptyReserve = (slots / 7) + 1; // keep this many empty
00196         mork_fill maxFill = slots - emptyReserve; // new max occupancy
00197         if ( maxFill > sMap_Fill ) // new max is bigger than old occupancy?
00198           sProbeMap_MaxFill = maxFill; // we can install new max for fill
00199         else
00200           this->GrowFailsMaxFillError(ev); // we have invariant failure
00201       }
00202       
00203       if ( ev->Bad() ) // rehash failed? need to revert map to last state?
00204         this->revert_map(ev, &old); // swap the vectors back again
00205 
00206       old.halt_map_scratch(ev); // remember to free the old arrays
00207     }
00208   }
00209   else ev->OutOfMemoryError();
00210   
00211   return ev->Good();
00212 }
00213 
00214 void morkProbeMap::revert_map(morkEnv* ev, morkMapScratch* ioScratch)
00215 {
00216   mork_count tempSlots = ioScratch->sMapScratch_Slots; // sMap_Slots  
00217   mork_u1* tempKeys = ioScratch->sMapScratch_Keys;     // sMap_Keys
00218   mork_u1* tempVals = ioScratch->sMapScratch_Vals;     // sMap_Vals
00219   
00220   ioScratch->sMapScratch_Slots = sMap_Slots;
00221   ioScratch->sMapScratch_Keys = sMap_Keys;
00222   ioScratch->sMapScratch_Vals = sMap_Vals;
00223   
00224   sMap_Slots = tempSlots;
00225   sMap_Keys = tempKeys;
00226   sMap_Vals = tempVals;
00227 }
00228 
00229 void morkProbeMap::put_probe_kv(morkEnv* ev,
00230   const void* inAppKey, const void* inAppVal, mork_pos inPos)
00231 {
00232   mork_u1* mapVal = 0;
00233   mork_u1* mapKey = 0;
00234 
00235   mork_num valSize = sMap_ValSize;
00236   if ( valSize && inAppVal ) // map holds values? caller sends value?
00237   {
00238     mork_u1* val = sMap_Vals + (valSize * inPos);
00239     if ( valSize == sizeof(mork_ip) && sMap_ValIsIP ) // int special case? 
00240       *((mork_ip*) val) = *((const mork_ip*) inAppVal);
00241     else
00242       mapVal = val; // show possible need to call ProbeMapPushIn()
00243   }
00244   if ( inAppKey ) // caller sends the key? 
00245   {
00246     mork_num keySize = sMap_KeySize;
00247     mork_u1* key = sMap_Keys + (keySize * inPos);
00248     if ( keySize == sizeof(mork_ip) && sMap_KeyIsIP ) // int special case? 
00249       *((mork_ip*) key) = *((const mork_ip*) inAppKey);
00250     else
00251       mapKey = key; // show possible need to call ProbeMapPushIn()
00252   }
00253   else
00254     ev->NilPointerError();
00255 
00256   if ( (  inAppVal && mapVal ) || ( inAppKey && mapKey ) )
00257     this->ProbeMapPushIn(ev, inAppKey, inAppVal, mapKey, mapVal);
00258 
00259   if ( sMap_Fill > sProbeMap_MaxFill )
00260     this->grow_probe_map(ev);
00261 }
00262 
00263 void morkProbeMap::get_probe_kv(morkEnv* ev,
00264   void* outAppKey, void* outAppVal, mork_pos inPos) const
00265 {
00266   const mork_u1* mapVal = 0;
00267   const mork_u1* mapKey = 0;
00268 
00269   mork_num valSize = sMap_ValSize;
00270   if ( valSize && outAppVal ) // map holds values? caller wants value?
00271   {
00272     const mork_u1* val = sMap_Vals + (valSize * inPos);
00273     if ( valSize == sizeof(mork_ip) && sMap_ValIsIP ) // int special case? 
00274       *((mork_ip*) outAppVal) = *((const mork_ip*) val);
00275     else
00276       mapVal = val; // show possible need to call ProbeMapPullOut()
00277   }
00278   if ( outAppKey ) // caller wants the key? 
00279   {
00280     mork_num keySize = sMap_KeySize;
00281     const mork_u1* key = sMap_Keys + (keySize * inPos);
00282     if ( keySize == sizeof(mork_ip) && sMap_KeyIsIP ) // int special case? 
00283       *((mork_ip*) outAppKey) = *((const mork_ip*) key);
00284     else
00285       mapKey = key; // show possible need to call ProbeMapPullOut()
00286   }
00287   if ( ( outAppVal && mapVal ) || ( outAppKey && mapKey ) )
00288     this->ProbeMapPullOut(ev, mapKey, mapVal, outAppKey, outAppVal);
00289 }
00290 
00291 mork_test
00292 morkProbeMap::find_key_pos(morkEnv* ev, const void* inAppKey,
00293   mork_u4 inHash, mork_pos* outPos) const
00294 {
00295   mork_u1* k = sMap_Keys;        // array of keys, each of size sMap_KeySize
00296   mork_num size = sMap_KeySize;  // number of bytes in each key
00297   mork_count slots = sMap_Slots; // total number of key buckets
00298   mork_pos i = inHash % slots;   // target hash bucket
00299   mork_pos startPos = i;         // remember start to detect
00300   
00301   mork_test outTest = this->MapTest(ev, k + (i * size), inAppKey);
00302   while ( outTest == morkTest_kMiss )
00303   {
00304     if ( ++i >= (mork_pos)slots ) // advancing goes beyond end? need to wrap around now?
00305       i = 0; // wrap around to first slot in map's hash table
00306       
00307     if ( i == startPos ) // no void slots were found anywhere in map?
00308     {
00309       this->WrapWithNoVoidSlotError(ev); // should never happen
00310       break; // end loop on kMiss; note caller expects either kVoid or kHit
00311     }
00312     outTest = this->MapTest(ev, k + (i * size), inAppKey);
00313   }
00314   *outPos = i;
00315   
00316   return outTest;
00317 }
00318  
00319 void morkProbeMap::probe_map_lazy_init(morkEnv* ev)
00320 {
00321   if ( this->need_lazy_init() && sMap_Fill == 0 ) // pending lazy action?
00322   {
00323     // The constructor cannot successfully call virtual ProbeMapClearKey(),
00324     // so we lazily do so now, when we add the first member to the map.
00325     
00326     mork_u1* keys = sMap_Keys;
00327     if ( keys ) // okay to call lazy virtual clear method on new map keys?
00328     {
00329       if ( sProbeMap_ZeroIsClearKey ) // zero is good enough to clear keys?
00330       {
00331         mork_num keyVolume = sMap_Slots * sMap_KeySize;
00332         if ( keyVolume )
00333           MORK_MEMSET(keys, 0, keyVolume);
00334       }
00335       else
00336         this->ProbeMapClearKey(ev, keys, sMap_Slots);
00337     }
00338     else
00339       this->MapNilKeysError(ev);
00340   }
00341   sProbeMap_LazyClearOnAdd = 0; // don't do this ever again
00342 }
00343 
00344 mork_bool
00345 morkProbeMap::MapAtPut(morkEnv* ev,
00346   const void* inAppKey, const void* inAppVal,
00347   void* outAppKey, void* outAppVal)
00348 {
00349   mork_bool outPut = morkBool_kFalse;
00350   
00351   if ( this->GoodProbeMap() ) /* looks good? */
00352   {
00353     if ( this->need_lazy_init() && sMap_Fill == 0 ) // pending lazy action?
00354       this->probe_map_lazy_init(ev);
00355           
00356     if ( ev->Good() )
00357     {
00358       mork_pos slotPos = 0;
00359       mork_u4 hash = this->MapHash(ev, inAppKey);
00360       mork_test test = this->find_key_pos(ev, inAppKey, hash, &slotPos);
00361       outPut = ( test == morkTest_kHit );
00362 
00363       if ( outPut ) // replacing an old assoc? no change in member count?
00364       {
00365         if ( outAppKey || outAppVal ) /* copy old before cobber? */
00366           this->get_probe_kv(ev, outAppKey, outAppVal, slotPos);
00367       }
00368       else // adding a new assoc increases membership by one
00369       {
00370         ++sMap_Fill; /* one more member in the collection */
00371       }
00372       
00373       if ( test != morkTest_kMiss ) /* found slot to hold new assoc? */
00374       {
00375         ++sMap_Seed; /* note the map has changed */
00376         this->put_probe_kv(ev, inAppKey, inAppVal, slotPos);
00377       }
00378     }
00379   }
00380   else this->ProbeMapBadTagError(ev);
00381   
00382   return outPut;
00383 }
00384     
00385 mork_bool
00386 morkProbeMap::MapAt(morkEnv* ev, const void* inAppKey,
00387     void* outAppKey, void* outAppVal)
00388 {
00389   if ( this->GoodProbeMap() ) /* looks good? */
00390   {
00391     if ( this->need_lazy_init() && sMap_Fill == 0 ) // pending lazy action?
00392       this->probe_map_lazy_init(ev);
00393           
00394     mork_pos slotPos = 0;
00395     mork_u4 hash = this->MapHash(ev, inAppKey);
00396     mork_test test = this->find_key_pos(ev, inAppKey, hash, &slotPos);
00397     if ( test == morkTest_kHit ) /* found an assoc pair for inAppKey? */
00398     {
00399       this->get_probe_kv(ev, outAppKey, outAppVal, slotPos);
00400       return morkBool_kTrue;
00401     }
00402   }
00403   else this->ProbeMapBadTagError(ev);
00404   
00405   return morkBool_kFalse;
00406 }
00407     
00408 mork_num
00409 morkProbeMap::MapCutAll(morkEnv* ev)
00410 {
00411   mork_num outCutAll = 0;
00412   
00413   if ( this->GoodProbeMap() ) /* looks good? */
00414   {
00415     outCutAll = sMap_Fill; /* number of members cut, which is all of them */
00416     
00417     if ( sMap_Keys && !sProbeMap_ZeroIsClearKey )
00418       this->ProbeMapClearKey(ev, sMap_Keys, sMap_Slots);
00419 
00420     sMap_Fill = 0; /* map now has no members */
00421   }
00422   else this->ProbeMapBadTagError(ev);
00423   
00424   return outCutAll;
00425 }
00426     
00427 // { ===== node interface =====
00428 
00429 /*virtual*/
00430 morkProbeMap::~morkProbeMap() // assert NodeStop() finished earlier
00431 {
00432   MORK_ASSERT(sMap_Keys==0);
00433   MORK_ASSERT(sProbeMap_Tag==0);
00434 }
00435 
00436 /*public virtual*/ void
00437 morkProbeMap::CloseMorkNode(morkEnv* ev) // CloseMap() only if open
00438 {
00439   if ( this->IsOpenNode() )
00440   {
00441     this->MarkClosing();
00442     this->CloseProbeMap(ev);
00443     this->MarkShut();
00444   }
00445 }
00446 
00447 void morkProbeMap::CloseProbeMap(morkEnv* ev)
00448 {
00449   if ( this )
00450   {
00451     if ( this->IsNode() )
00452     {
00453       nsIMdbHeap* heap = sMap_Heap;
00454       if ( heap ) // able to free map arrays?
00455       {
00456         void* block = sMap_Keys;
00457         if ( block )
00458         {
00459           heap->Free(ev->AsMdbEnv(), block);
00460           sMap_Keys = 0;
00461         }
00462           
00463         block = sMap_Vals;
00464         if ( block )
00465         {
00466           heap->Free(ev->AsMdbEnv(), block);
00467           sMap_Vals = 0;
00468         }
00469       }
00470       sMap_Keys = 0;
00471       sMap_Vals = 0;
00472       
00473       this->CloseNode(ev);
00474       sProbeMap_Tag = 0;
00475       sProbeMap_MaxFill = 0;
00476       
00477       this->MarkShut();
00478     }
00479     else
00480       this->NonNodeError(ev);
00481   }
00482   else
00483     ev->NilPointerError();
00484 }
00485 
00486 void*
00487 morkProbeMap::clear_alloc(morkEnv* ev, mork_size inSize)
00488 {
00489   void* p = 0;
00490   nsIMdbHeap* heap = sMap_Heap;
00491   if ( heap )
00492   {
00493     if ( heap->Alloc(ev->AsMdbEnv(), inSize, (void**) &p) == 0 && p )
00494     {
00495       MORK_MEMSET(p, 0, inSize);
00496       return p;
00497     }
00498   }
00499   else
00500     ev->NilPointerError();
00501     
00502   return (void*) 0;
00503 }
00504 
00505 /*| map_new_keys: allocate an array of inSlots new keys filled with zero.
00506 **| (cf IronDoc's FeHashTable_new_keys())
00507 |*/
00508 mork_u1*
00509 morkProbeMap::map_new_keys(morkEnv* ev, mork_num inSlots)
00510 {
00511   mork_num size = inSlots * sMap_KeySize;
00512   return (mork_u1*) this->clear_alloc(ev, size);
00513 }
00514 
00515 /*| map_new_vals: allocate an array of inSlots new values filled with zero.
00516 **| When values are zero sized, we just return a null pointer.
00517 **|
00518 **| (cf IronDoc's FeHashTable_new_values())
00519 |*/
00520 mork_u1*
00521 morkProbeMap::map_new_vals(morkEnv* ev, mork_num inSlots)
00522 {
00523   mork_u1* values = 0;
00524   mork_num size = inSlots * sMap_ValSize;
00525   if ( size )
00526     values = (mork_u1*) this->clear_alloc(ev, size);
00527   return values;
00528 }
00529 
00530 
00531 void morkProbeMap::MapSeedOutOfSyncError(morkEnv* ev)
00532 {
00533   ev->NewError("sMap_Seed out of sync");
00534 }
00535 
00536 void morkProbeMap::MapFillUnderflowWarning(morkEnv* ev)
00537 {
00538   ev->NewWarning("sMap_Fill underflow");
00539 }
00540 
00541 void morkProbeMap::MapNilKeysError(morkEnv* ev)
00542 {
00543   ev->NewError("nil sMap_Keys");
00544 }
00545 
00546 void morkProbeMap::MapZeroKeySizeError(morkEnv* ev)
00547 {
00548   ev->NewError("zero sMap_KeySize");
00549 }
00550 
00551 /*static*/
00552 void morkProbeMap::ProbeMapCutError(morkEnv* ev)
00553 {
00554   ev->NewError("morkProbeMap cannot cut");
00555 }
00556 
00557 
00558 void morkProbeMap::init_probe_map(morkEnv* ev, mork_size inSlots)
00559 {
00560   // Note we cannot successfully call virtual ProbeMapClearKey() when we
00561   // call init_probe_map() inside the constructor; so we leave this problem
00562   // to the caller.  (The constructor will call ProbeMapClearKey() later
00563   // after setting a suitable lazy flag to show this action is pending.)
00564 
00565   if ( ev->Good() )
00566   {
00567     morkMapScratch old;
00568 
00569     if ( inSlots < 7 ) // capacity too small?
00570       inSlots = 7; // increase to reasonable minimum
00571     else if ( inSlots > (128 * 1024) ) // requested capacity too big?
00572       inSlots = (128 * 1024); // decrease to reasonable maximum
00573       
00574     if ( this->new_slots(ev, &old, inSlots) )
00575       sProbeMap_Tag = morkProbeMap_kTag;
00576       
00577     mork_count slots = sMap_Slots;
00578     mork_num emptyReserve = (slots / 7) + 1; // keep this many empty
00579     sProbeMap_MaxFill = slots - emptyReserve;
00580 
00581     MORK_MEMSET(&old, 0, sizeof(morkMapScratch)); // don't bother halting
00582   }
00583 }
00584 
00585 mork_bool
00586 morkProbeMap::new_slots(morkEnv* ev, morkMapScratch* old, mork_num inSlots)
00587 {
00588   mork_bool outNew = morkBool_kFalse;
00589   
00590   // Note we cannot successfully call virtual ProbeMapClearKey() when we
00591   // call new_slots() inside the constructor; so we leave this problem
00592   // to the caller.  (The constructor will call ProbeMapClearKey() later
00593   // after setting a suitable lazy flag to show this action is pending.)
00594     
00595   // allocate every new array before we continue:
00596   mork_u1* newKeys = this->map_new_keys(ev, inSlots);
00597   mork_u1* newVals = this->map_new_vals(ev, inSlots);
00598   
00599   // okay for newVals to be null when values are zero sized?
00600   mork_bool okayValues = ( newVals || !sMap_ValSize );
00601   
00602   if ( newKeys && okayValues )
00603   {
00604     outNew = morkBool_kTrue; // we created every array needed
00605 
00606     // init mapScratch using slots from current map:
00607     old->sMapScratch_Heap = sMap_Heap;
00608     
00609     old->sMapScratch_Slots = sMap_Slots;
00610     old->sMapScratch_Keys = sMap_Keys;
00611     old->sMapScratch_Vals = sMap_Vals;
00612     
00613     // replace all map array slots using the newly allocated members:
00614     ++sMap_Seed; // the map has changed
00615     sMap_Keys = newKeys;
00616     sMap_Vals = newVals;
00617     sMap_Slots = inSlots;
00618   }
00619   else // free any allocations if only partially successful
00620   {
00621     nsIMdbHeap* heap = sMap_Heap;
00622     if ( newKeys )
00623       heap->Free(ev->AsMdbEnv(), newKeys);
00624     if ( newVals )
00625       heap->Free(ev->AsMdbEnv(), newVals);
00626     
00627     MORK_MEMSET(old, 0, sizeof(morkMapScratch)); // zap scratch space
00628   }
00629   
00630   return outNew;
00631 }
00632 
00633 void
00634 morkProbeMap::clear_probe_map(morkEnv* ev, nsIMdbHeap* ioMapHeap)
00635 {
00636   sProbeMap_Tag = 0;
00637   sMap_Seed = 0;
00638   sMap_Slots = 0;
00639   sMap_Fill = 0;
00640   sMap_Keys = 0;
00641   sMap_Vals = 0;
00642   sProbeMap_MaxFill = 0;
00643   
00644   sMap_Heap = ioMapHeap;
00645   if ( !ioMapHeap )
00646     ev->NilPointerError();
00647 }
00648 
00649 morkProbeMap::morkProbeMap(morkEnv* ev, const morkUsage& inUsage,
00650   nsIMdbHeap* ioNodeHeap,
00651   mork_size inKeySize, mork_size inValSize,
00652   nsIMdbHeap* ioMapHeap, mork_size inSlots,
00653   mork_bool inZeroIsClearKey)
00654   
00655 : morkNode(ev, inUsage, ioNodeHeap)
00656 , sMap_Heap( ioMapHeap )
00657     
00658 , sMap_Keys( 0 )
00659 , sMap_Vals( 0 )
00660   
00661 , sMap_Seed( 0 )   // change count of members or structure
00662     
00663 , sMap_Slots( 0 )  // count of slots in the hash table
00664 , sMap_Fill( 0 )   // number of used slots in the hash table
00665 
00666 , sMap_KeySize( 0 ) // size of each key (cannot be zero)
00667 , sMap_ValSize( 0 ) // size of each val (zero allowed)
00668   
00669 , sMap_KeyIsIP( morkBool_kFalse ) // sMap_KeySize == sizeof(mork_ip)
00670 , sMap_ValIsIP( morkBool_kFalse ) // sMap_ValSize == sizeof(mork_ip)
00671 
00672 , sProbeMap_MaxFill( 0 )
00673 , sProbeMap_LazyClearOnAdd( 0 )
00674 , sProbeMap_ZeroIsClearKey( inZeroIsClearKey )
00675 , sProbeMap_Tag( 0 )
00676 {
00677   // Note we cannot successfully call virtual ProbeMapClearKey() when we
00678   // call init_probe_map() inside the constructor; so we leave this problem
00679   // to the caller.  (The constructor will call ProbeMapClearKey() later
00680   // after setting a suitable lazy flag to show this action is pending.)
00681 
00682   if ( ev->Good() )
00683   {
00684     this->clear_probe_map(ev, ioMapHeap);
00685     if ( ev->Good() )
00686     {      
00687       sMap_KeySize = inKeySize;
00688       sMap_ValSize = inValSize;
00689       sMap_KeyIsIP = ( inKeySize == sizeof(mork_ip) );
00690       sMap_ValIsIP = ( inValSize == sizeof(mork_ip) );
00691       
00692       this->init_probe_map(ev, inSlots);
00693       if ( ev->Good() )
00694       {
00695         if ( !inZeroIsClearKey ) // must lazy clear later with virtual method?
00696           sProbeMap_LazyClearOnAdd = morkProbeMap_kLazyClearOnAdd;
00697           
00698         mNode_Derived = morkDerived_kProbeMap;
00699       }
00700     }
00701   }
00702 }
00703 
00704 /*============================================================================*/
00705 
00706 /*virtual*/ mork_test // hit(a,b) implies hash(a) == hash(b)
00707 morkProbeMap::MapTest(morkEnv* ev,
00708   const void* inMapKey, const void* inAppKey) const
00709   // Note inMapKey is always a key already stored in the map, while inAppKey
00710   //   is always a method argument parameter from a client method call.
00711   //   This matters the most in morkProbeMap subclasses, which have the
00712   //   responsibility of putting 'app' keys into slots for 'map' keys, and
00713   //   the bit pattern representation might be different in such cases.
00714   // morkTest_kHit means that inMapKey equals inAppKey (and this had better
00715   //   also imply that hash(inMapKey) == hash(inAppKey)).
00716   // morkTest_kMiss means that inMapKey does NOT equal inAppKey (but this
00717   //   implies nothing at all about hash(inMapKey) and hash(inAppKey)).
00718   // morkTest_kVoid means that inMapKey is not a valid key bit pattern,
00719   //   which means that key slot in the map is not being used.  Note that
00720   //   kVoid is only expected as a return value in morkProbeMap subclasses,
00721   //   because morkProbeMap must ask whether a key slot is used or not. 
00722   //   morkChainMap however, always knows when a key slot is used, so only
00723   //   key slots expected to have valid bit patterns will be presented to
00724   //   the MapTest() methods for morkChainMap subclasses.
00725   //
00726   // NOTE: it is very important that subclasses correctly return the value
00727   // morkTest_kVoid whenever the slot for inMapKey contains a bit pattern
00728   // that means the slot is not being used, because this is the only way a
00729   // probe map can terminate an unsuccessful search for a key in the map.
00730 {
00731   mork_size keySize = sMap_KeySize;
00732   if ( keySize == sizeof(mork_ip) && sMap_KeyIsIP )
00733   {
00734     mork_ip mapKey = *((const mork_ip*) inMapKey);
00735     if ( mapKey == *((const mork_ip*) inAppKey) )
00736       return morkTest_kHit;
00737     else
00738     {
00739       return ( mapKey )? morkTest_kMiss : morkTest_kVoid;
00740     }
00741   }
00742   else
00743   {
00744     mork_bool allSame = morkBool_kTrue;
00745     mork_bool allZero = morkBool_kTrue;
00746     const mork_u1* ak = (const mork_u1*) inAppKey;
00747     const mork_u1* mk = (const mork_u1*) inMapKey;
00748     const mork_u1* end = mk + keySize;
00749     --mk; // prepare for preincrement:
00750     while ( ++mk < end )
00751     {
00752       mork_u1 byte = *mk;
00753       if ( byte ) // any nonzero byte in map key means slot is not nil?
00754         allZero = morkBool_kFalse;
00755       if ( byte != *ak++ ) // bytes differ in map and app keys?
00756         allSame = morkBool_kFalse;
00757     }
00758     if ( allSame )
00759       return morkTest_kHit;
00760     else
00761       return ( allZero )? morkTest_kVoid : morkTest_kMiss;
00762   }
00763 }
00764 
00765 /*virtual*/ mork_u4 // hit(a,b) implies hash(a) == hash(b)
00766 morkProbeMap::MapHash(morkEnv* ev, const void* inAppKey) const
00767 {
00768   mork_size keySize = sMap_KeySize;
00769   if ( keySize == sizeof(mork_ip) && sMap_KeyIsIP )
00770   {
00771     return *((const mork_ip*) inAppKey);
00772   }
00773   else
00774   {
00775     const mork_u1* key = (const mork_u1*) inAppKey;
00776     const mork_u1* end = key + keySize;
00777     --key; // prepare for preincrement:
00778     while ( ++key < end )
00779     {
00780       if ( *key ) // any nonzero byte in map key means slot is not nil?
00781         return morkBool_kFalse;
00782     }
00783     return morkBool_kTrue;
00784   }
00785   return (mork_u4) NS_PTR_TO_INT32(inAppKey);
00786 }
00787 
00788 
00789 /*============================================================================*/
00790 
00791 /*virtual*/ mork_u4
00792 morkProbeMap::ProbeMapHashMapKey(morkEnv* ev, const void* inMapKey) const
00793   // ProbeMapHashMapKey() does logically the same thing as MapHash(), and
00794   // the default implementation actually calls virtual MapHash().  However,
00795   // Subclasses must override this method whenever the formats of keys in
00796   // the map differ from app keys outside the map, because MapHash() only
00797   // works on keys in 'app' format, while ProbeMapHashMapKey() only works
00798   // on keys in 'map' format.  This method is called in order to rehash all
00799   // map keys when a map is grown, and this causes all old map members to
00800   // move into new slot locations.
00801   //
00802   // Note it is absolutely imperative that a hash for a key in 'map' format
00803   // be exactly the same the hash of the same key in 'app' format, or else
00804   // maps will seem corrupt later when keys in 'app' format cannot be found.
00805 {
00806   return this->MapHash(ev, inMapKey);
00807 }
00808 
00809 /*virtual*/ mork_bool
00810 morkProbeMap::ProbeMapIsKeyNil(morkEnv* ev, void* ioMapKey)
00811   // ProbeMapIsKeyNil() must say whether the representation of logical 'nil'
00812   // is currently found inside the key at ioMapKey, for a key found within
00813   // the map.  The the map iterator uses this method to find map keys that
00814   // are actually being used for valid map associations; otherwise the
00815   // iterator cannot determine which map slots actually denote used keys.
00816   // The default method version returns true if all the bits equal zero.
00817 {
00818   if ( sMap_KeySize == sizeof(mork_ip) && sMap_KeyIsIP )
00819   {
00820     return !*((const mork_ip*) ioMapKey);
00821   }
00822   else
00823   {
00824     const mork_u1* key = (const mork_u1*) ioMapKey;
00825     const mork_u1* end = key + sMap_KeySize;
00826     --key; // prepare for preincrement:
00827     while ( ++key < end )
00828     {
00829       if ( *key ) // any nonzero byte in map key means slot is not nil?
00830         return morkBool_kFalse;
00831     }
00832     return morkBool_kTrue;
00833   }
00834 }
00835 
00836 /*virtual*/ void
00837 morkProbeMap::ProbeMapClearKey(morkEnv* ev, // put 'nil' alls keys inside map
00838   void* ioMapKey, mork_count inKeyCount) // array of keys inside map
00839   // ProbeMapClearKey() must put some representation of logical 'nil' into
00840   // every key slot in the map, such that MapTest() will later recognize
00841   // that this bit pattern shows each key slot is not actually being used.
00842   //
00843   // This method is typically called whenever the map is either created or
00844   // grown into a larger size, where ioMapKey is a pointer to an array of
00845   // inKeyCount keys, where each key is this->MapKeySize() bytes in size.
00846   // Note that keys are assumed immediately adjacent with no padding, so
00847   // if any alignment requirements must be met, then subclasses should have
00848   // already accounted for this when specifying a key size in the map.
00849   //
00850   // Since this method will be called when a map is being grown in size,
00851   // nothing should be assumed about the state slots of the map, since the
00852   // ioMapKey array might not yet live in sMap_Keys, and the array length
00853   // inKeyCount might not yet live in sMap_Slots.  However, the value kept
00854   // in sMap_KeySize never changes, so this->MapKeySize() is always correct.
00855 {
00856   if ( ioMapKey && inKeyCount )
00857   {
00858     MORK_MEMSET(ioMapKey, 0, (inKeyCount * sMap_KeySize));
00859   }
00860   else
00861     ev->NilPointerWarning();
00862 }
00863 
00864 /*virtual*/ void
00865 morkProbeMap::ProbeMapPushIn(morkEnv* ev, // move (key,val) into the map
00866   const void* inAppKey, const void* inAppVal, // (key,val) outside map
00867   void* outMapKey, void* outMapVal)      // (key,val) inside map
00868   // This method actually puts keys and vals in the map in suitable format.
00869   //
00870   // ProbeMapPushIn() must copy a caller key and value in 'app' format
00871   // into the map slots provided, which are in 'map' format.  When the
00872   // 'app' and 'map' formats are identical, then this is just a bitwise
00873   // copy of this->MapKeySize() key bytes and this->MapValSize() val bytes,
00874   // and this is exactly what the default implementation performs.  However,
00875   // if 'app' and 'map' formats are different, and MapTest() depends on this
00876   // difference in format, then subclasses must override this method to do
00877   // whatever is necessary to store the input app key in output map format.
00878   //
00879   // Do NOT write more than this->MapKeySize() bytes of a map key, or more
00880   // than this->MapValSize() bytes of a map val, or corruption might ensue.
00881   //
00882   // The inAppKey and inAppVal parameters are the same ones passed into a
00883   // call to MapAtPut(), and the outMapKey and outMapVal parameters are ones
00884   // determined by how the map currently positions key inAppKey in the map.
00885   //
00886   // Note any key or val parameter can be a null pointer, in which case
00887   // this method must do nothing with those parameters.  In particular, do
00888   // no key move at all when either inAppKey or outMapKey is nil, and do
00889   // no val move at all when either inAppVal or outMapVal is nil.  Note that
00890   // outMapVal should always be nil when this->MapValSize() is nil.
00891 {
00892 }
00893 
00894 /*virtual*/ void
00895 morkProbeMap::ProbeMapPullOut(morkEnv* ev, // move (key,val) out from the map
00896   const void* inMapKey, const void* inMapVal, // (key,val) inside map
00897   void* outAppKey, void* outAppVal) const    // (key,val) outside map
00898   // This method actually gets keys and vals from the map in suitable format.
00899   //
00900   // ProbeMapPullOut() must copy a key and val in 'map' format into the
00901   // caller key and val slots provided, which are in 'app' format.  When the
00902   // 'app' and 'map' formats are identical, then this is just a bitwise
00903   // copy of this->MapKeySize() key bytes and this->MapValSize() val bytes,
00904   // and this is exactly what the default implementation performs.  However,
00905   // if 'app' and 'map' formats are different, and MapTest() depends on this
00906   // difference in format, then subclasses must override this method to do
00907   // whatever is necessary to store the input map key in output app format.
00908   //
00909   // The outAppKey and outAppVal parameters are the same ones passed into a
00910   // call to either MapAtPut() or MapAt(), while inMapKey and inMapVal are
00911   // determined by how the map currently positions the target key in the map.
00912   //
00913   // Note any key or val parameter can be a null pointer, in which case
00914   // this method must do nothing with those parameters.  In particular, do
00915   // no key move at all when either inMapKey or outAppKey is nil, and do
00916   // no val move at all when either inMapVal or outAppVal is nil.  Note that
00917   // inMapVal should always be nil when this->MapValSize() is nil.
00918 {
00919 }
00920 
00921 
00922 /*============================================================================*/
00923 /* morkProbeMapIter */
00924 
00925 morkProbeMapIter::morkProbeMapIter(morkEnv* ev, morkProbeMap* ioMap)
00926 : sProbeMapIter_Map( 0 )
00927 , sProbeMapIter_Seed( 0 )
00928 , sProbeMapIter_HereIx( morkProbeMapIter_kBeforeIx )
00929 {
00930   if ( ioMap )
00931   {
00932     if ( ioMap->GoodProbeMap() )
00933     {
00934       if ( ioMap->need_lazy_init() ) // pending lazy action?
00935         ioMap->probe_map_lazy_init(ev);
00936         
00937       sProbeMapIter_Map = ioMap;
00938       sProbeMapIter_Seed = ioMap->sMap_Seed;
00939     }
00940     else ioMap->ProbeMapBadTagError(ev);
00941   }
00942   else ev->NilPointerError();
00943 }
00944 
00945 void morkProbeMapIter::CloseMapIter(morkEnv* ev)
00946 {
00947   MORK_USED_1(ev);
00948   sProbeMapIter_Map = 0;
00949   sProbeMapIter_Seed = 0;
00950 
00951   sProbeMapIter_HereIx = morkProbeMapIter_kAfterIx;
00952 }
00953 
00954 morkProbeMapIter::morkProbeMapIter( )
00955 // zero most slots; caller must call InitProbeMapIter()
00956 {
00957   sProbeMapIter_Map = 0;
00958   sProbeMapIter_Seed = 0;
00959 
00960   sProbeMapIter_HereIx = morkProbeMapIter_kBeforeIx;
00961 }
00962 
00963 void morkProbeMapIter::InitProbeMapIter(morkEnv* ev, morkProbeMap* ioMap)
00964 {
00965   sProbeMapIter_Map = 0;
00966   sProbeMapIter_Seed = 0;
00967 
00968   sProbeMapIter_HereIx = morkProbeMapIter_kBeforeIx;
00969 
00970   if ( ioMap )
00971   {
00972     if ( ioMap->GoodProbeMap() )
00973     {
00974       if ( ioMap->need_lazy_init() ) // pending lazy action?
00975         ioMap->probe_map_lazy_init(ev);
00976         
00977       sProbeMapIter_Map = ioMap;
00978       sProbeMapIter_Seed = ioMap->sMap_Seed;
00979     }
00980     else ioMap->ProbeMapBadTagError(ev);
00981   }
00982   else ev->NilPointerError();
00983 }
00984  
00985 mork_bool morkProbeMapIter::IterFirst(morkEnv* ev,
00986   void* outAppKey, void* outAppVal)
00987 {
00988   sProbeMapIter_HereIx = morkProbeMapIter_kAfterIx; // default to done
00989   morkProbeMap* map = sProbeMapIter_Map;
00990   
00991   if ( map && map->GoodProbeMap() ) /* looks good? */
00992   {
00993     sProbeMapIter_Seed = map->sMap_Seed; /* sync the seeds */
00994     
00995     mork_u1* k = map->sMap_Keys;  // array of keys, each of size sMap_KeySize
00996     mork_num size = map->sMap_KeySize;  // number of bytes in each key
00997     mork_count slots = map->sMap_Slots; // total number of key buckets
00998     mork_pos here = 0;  // first hash bucket
00999     
01000     while ( here < (mork_pos)slots )
01001     {
01002       if ( !map->ProbeMapIsKeyNil(ev, k + (here * size)) )
01003       {
01004         map->get_probe_kv(ev, outAppKey, outAppVal, here);
01005         
01006         sProbeMapIter_HereIx = (mork_i4) here;
01007         return morkBool_kTrue;
01008       }
01009       ++here; // next bucket
01010     } 
01011   }
01012   else map->ProbeMapBadTagError(ev);
01013 
01014   return morkBool_kFalse;
01015 }
01016 
01017 mork_bool morkProbeMapIter::IterNext(morkEnv* ev,
01018   void* outAppKey, void* outAppVal)
01019 {
01020   morkProbeMap* map = sProbeMapIter_Map;
01021   
01022   if ( map && map->GoodProbeMap() ) /* looks good? */
01023   {    
01024     if ( sProbeMapIter_Seed == map->sMap_Seed ) /* in sync? */
01025     {
01026       if ( sProbeMapIter_HereIx != morkProbeMapIter_kAfterIx )
01027       {
01028         mork_pos here = (mork_pos) sProbeMapIter_HereIx;
01029         if ( sProbeMapIter_HereIx < 0 )
01030           here = 0;
01031         else
01032           ++here;
01033           
01034         sProbeMapIter_HereIx = morkProbeMapIter_kAfterIx; // default to done
01035 
01036         mork_u1* k = map->sMap_Keys;  // key array, each of size sMap_KeySize
01037         mork_num size = map->sMap_KeySize;  // number of bytes in each key
01038         mork_count slots = map->sMap_Slots; // total number of key buckets
01039         
01040         while ( here < (mork_pos)slots )
01041         {
01042           if ( !map->ProbeMapIsKeyNil(ev, k + (here * size)) )
01043           {
01044             map->get_probe_kv(ev, outAppKey, outAppVal, here);
01045             
01046             sProbeMapIter_HereIx = (mork_i4) here;
01047             return morkBool_kTrue;
01048           }
01049           ++here; // next bucket
01050         } 
01051       }
01052     }
01053     else map->MapSeedOutOfSyncError(ev);
01054   }
01055   else map->ProbeMapBadTagError(ev);
01056 
01057   return morkBool_kFalse;
01058 }
01059 
01060 mork_bool morkProbeMapIter::IterHere(morkEnv* ev,
01061   void* outAppKey, void* outAppVal)
01062 {
01063   morkProbeMap* map = sProbeMapIter_Map;
01064   
01065   if ( map && map->GoodProbeMap() ) /* looks good? */
01066   {    
01067     if ( sProbeMapIter_Seed == map->sMap_Seed ) /* in sync? */
01068     {
01069       mork_pos here = (mork_pos) sProbeMapIter_HereIx;
01070       mork_count slots = map->sMap_Slots; // total number of key buckets
01071       if ( sProbeMapIter_HereIx >= 0 && (here < (mork_pos)slots))
01072       {
01073         mork_u1* k = map->sMap_Keys;  // key array, each of size sMap_KeySize
01074         mork_num size = map->sMap_KeySize;  // number of bytes in each key
01075 
01076         if ( !map->ProbeMapIsKeyNil(ev, k + (here * size)) )
01077         {
01078           map->get_probe_kv(ev, outAppKey, outAppVal, here);
01079           return morkBool_kTrue;
01080         }
01081       }
01082     }
01083     else map->MapSeedOutOfSyncError(ev);
01084   }
01085   else map->ProbeMapBadTagError(ev);
01086 
01087   return morkBool_kFalse;
01088 }
01089 
01090 mork_change*
01091 morkProbeMapIter::First(morkEnv* ev, void* outKey, void* outVal)
01092 {
01093   if ( this->IterFirst(ev, outKey, outVal) )
01094     return &sProbeMapIter_Change;
01095   
01096   return (mork_change*) 0;
01097 }
01098 
01099 mork_change*
01100 morkProbeMapIter::Next(morkEnv* ev, void* outKey, void* outVal)
01101 {
01102   if ( this->IterNext(ev, outKey, outVal) )
01103     return &sProbeMapIter_Change;
01104   
01105   return (mork_change*) 0;
01106 }
01107 
01108 mork_change*
01109 morkProbeMapIter::Here(morkEnv* ev, void* outKey, void* outVal)
01110 {
01111   if ( this->IterHere(ev, outKey, outVal) )
01112     return &sProbeMapIter_Change;
01113   
01114   return (mork_change*) 0;
01115 }
01116 
01117 mork_change*
01118 morkProbeMapIter::CutHere(morkEnv* ev, void* outKey, void* outVal)
01119 {
01120   morkProbeMap::ProbeMapCutError(ev);
01121   
01122   return (mork_change*) 0;
01123 }
01124 
01125 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
01126 
01127 // NOTE: the following methods ONLY work for sMap_ValIsIP pointer values.
01128 // (Note the implied assumption that zero is never a good value pattern.)
01129 
01130 void* morkProbeMapIter::IterFirstVal(morkEnv* ev, void* outKey)
01131 // equivalent to { void* v=0; this->IterFirst(ev, outKey, &v); return v; }
01132 {
01133   morkProbeMap* map = sProbeMapIter_Map;
01134   if ( map )
01135   {
01136     if ( map->sMap_ValIsIP )
01137     {
01138       void* v = 0;
01139       this->IterFirst(ev, outKey, &v);
01140       return v;
01141     }
01142     else
01143       map->MapValIsNotIPError(ev);
01144   }
01145   return (void*) 0;
01146 }
01147 
01148 void* morkProbeMapIter::IterNextVal(morkEnv* ev, void* outKey)
01149 // equivalent to { void* v=0; this->IterNext(ev, outKey, &v); return v; }
01150 {
01151   morkProbeMap* map = sProbeMapIter_Map;
01152   if ( map )
01153   {
01154     if ( map->sMap_ValIsIP )
01155     {
01156       void* v = 0;
01157       this->IterNext(ev, outKey, &v);
01158       return v;
01159     }
01160     else
01161       map->MapValIsNotIPError(ev);
01162   }
01163   return (void*) 0;
01164 }
01165 
01166 void* morkProbeMapIter::IterHereVal(morkEnv* ev, void* outKey)
01167 // equivalent to { void* v=0; this->IterHere(ev, outKey, &v); return v; }
01168 {
01169   morkProbeMap* map = sProbeMapIter_Map;
01170   if ( map )
01171   {
01172     if ( map->sMap_ValIsIP )
01173     {
01174       void* v = 0;
01175       this->IterHere(ev, outKey, &v);
01176       return v;
01177     }
01178     else
01179       map->MapValIsNotIPError(ev);
01180   }
01181   return (void*) 0;
01182 }
01183 
01184 // NOTE: the following methods ONLY work for sMap_KeyIsIP pointer values.
01185 // (Note the implied assumption that zero is never a good key pattern.)
01186 
01187 void* morkProbeMapIter::IterFirstKey(morkEnv* ev)
01188 // equivalent to { void* k=0; this->IterFirst(ev, &k, 0); return k; }
01189 {
01190   morkProbeMap* map = sProbeMapIter_Map;
01191   if ( map )
01192   {
01193     if ( map->sMap_KeyIsIP )
01194     {
01195       void* k = 0;
01196       this->IterFirst(ev, &k, (void*) 0);
01197       return k;
01198     }
01199     else
01200       map->MapKeyIsNotIPError(ev);
01201   }
01202   return (void*) 0;
01203 }
01204 
01205 void* morkProbeMapIter::IterNextKey(morkEnv* ev)
01206 // equivalent to { void* k=0; this->IterNext(ev, &k, 0); return k; }
01207 {
01208   morkProbeMap* map = sProbeMapIter_Map;
01209   if ( map )
01210   {
01211     if ( map->sMap_KeyIsIP )
01212     {
01213       void* k = 0;
01214       this->IterNext(ev, &k, (void*) 0);
01215       return k;
01216     }
01217     else
01218       map->MapKeyIsNotIPError(ev);
01219   }
01220   return (void*) 0;
01221 }
01222 
01223 void* morkProbeMapIter::IterHereKey(morkEnv* ev)
01224 // equivalent to { void* k=0; this->IterHere(ev, &k, 0); return k; }
01225 {
01226   morkProbeMap* map = sProbeMapIter_Map;
01227   if ( map )
01228   {
01229     if ( map->sMap_KeyIsIP )
01230     {
01231       void* k = 0;
01232       this->IterHere(ev, &k, (void*) 0);
01233       return k;
01234     }
01235     else
01236       map->MapKeyIsNotIPError(ev);
01237   }
01238   return (void*) 0;
01239 }
01240 
01241 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789