GME  13
RefHash2KeysTableOf.c
Go to the documentation of this file.
00001 /*
00002  * Licensed to the Apache Software Foundation (ASF) under one or more
00003  * contributor license agreements.  See the NOTICE file distributed with
00004  * this work for additional information regarding copyright ownership.
00005  * The ASF licenses this file to You under the Apache License, Version 2.0
00006  * (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  *
00009  *      http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 /*
00019  * $Id: RefHash2KeysTableOf.c 679340 2008-07-24 10:28:29Z borisk $
00020  */
00021 
00022 
00023 // ---------------------------------------------------------------------------
00024 //  Include
00025 // ---------------------------------------------------------------------------
00026 #if defined(XERCES_TMPLSINC)
00027 #include <xercesc/util/RefHash2KeysTableOf.hpp>
00028 #endif
00029 
00030 #include <xercesc/util/Janitor.hpp>
00031 #include <xercesc/util/NullPointerException.hpp>
00032 #include <assert.h>
00033 #include <new>
00034 
00035 XERCES_CPP_NAMESPACE_BEGIN
00036 
00037 // ---------------------------------------------------------------------------
00038 //  RefHash2KeysTableOf: Constructors and Destructor
00039 // ---------------------------------------------------------------------------
00040 
00041 template <class TVal, class THasher>
00042 RefHash2KeysTableOf<TVal, THasher>::RefHash2KeysTableOf(
00043   const XMLSize_t modulus,
00044   MemoryManager* const manager)
00045 
00046     : fMemoryManager(manager)
00047     , fAdoptedElems(true)
00048     , fBucketList(0)
00049     , fHashModulus(modulus)
00050     , fCount(0)
00051 {
00052     initialize(modulus);
00053 }
00054 
00055 template <class TVal, class THasher>
00056 RefHash2KeysTableOf<TVal, THasher>::RefHash2KeysTableOf(
00057   const XMLSize_t modulus,
00058   const THasher& hasher,
00059   MemoryManager* const manager)
00060 
00061     : fMemoryManager(manager)
00062     , fAdoptedElems(true)
00063     , fBucketList(0)
00064     , fHashModulus(modulus)
00065     , fCount(0)
00066     , fHasher (hasher)
00067 {
00068     initialize(modulus);
00069 }
00070 
00071 template <class TVal, class THasher>
00072 RefHash2KeysTableOf<TVal, THasher>::RefHash2KeysTableOf(
00073   const XMLSize_t modulus,
00074   const bool adoptElems,
00075   MemoryManager* const manager)
00076 
00077     : fMemoryManager(manager)
00078     , fAdoptedElems(adoptElems)
00079     , fBucketList(0)
00080     , fHashModulus(modulus)
00081     , fCount(0)
00082 
00083 {
00084     initialize(modulus);
00085 }
00086 
00087 template <class TVal, class THasher>
00088 RefHash2KeysTableOf<TVal, THasher>::RefHash2KeysTableOf(
00089   const XMLSize_t modulus,
00090   const bool adoptElems,
00091   const THasher& hasher,
00092   MemoryManager* const manager)
00093 
00094     : fMemoryManager(manager)
00095     , fAdoptedElems(adoptElems)
00096     , fBucketList(0)
00097     , fHashModulus(modulus)
00098     , fCount(0)
00099     , fHasher (hasher)
00100 {
00101     initialize(modulus);
00102 }
00103 
00104 template <class TVal, class THasher>
00105 void RefHash2KeysTableOf<TVal, THasher>::initialize(const XMLSize_t modulus)
00106 {
00107     if (modulus == 0)
00108         ThrowXMLwithMemMgr(IllegalArgumentException, XMLExcepts::HshTbl_ZeroModulus, fMemoryManager);
00109 
00110     // Allocate the bucket list and zero them
00111     fBucketList = (RefHash2KeysTableBucketElem<TVal>**) fMemoryManager->allocate
00112     (
00113         fHashModulus * sizeof(RefHash2KeysTableBucketElem<TVal>*)
00114     ); //new RefHash2KeysTableBucketElem<TVal>*[fHashModulus];
00115     memset(fBucketList, 0, sizeof(fBucketList[0]) * fHashModulus);
00116 }
00117 
00118 template <class TVal, class THasher>
00119 RefHash2KeysTableOf<TVal, THasher>::~RefHash2KeysTableOf()
00120 {
00121     removeAll();
00122 
00123     // Then delete the bucket list & hasher
00124     fMemoryManager->deallocate(fBucketList); //delete [] fBucketList;
00125     fBucketList = 0;
00126 }
00127 
00128 
00129 // ---------------------------------------------------------------------------
00130 //  RefHash2KeysTableOf: Element management
00131 // ---------------------------------------------------------------------------
00132 template <class TVal, class THasher>
00133 bool RefHash2KeysTableOf<TVal, THasher>::isEmpty() const
00134 {
00135     return (fCount==0);
00136 }
00137 
00138 template <class TVal, class THasher>
00139 bool RefHash2KeysTableOf<TVal, THasher>::
00140 containsKey(const void* const key1, const int key2) const
00141 {
00142     XMLSize_t hashVal;
00143     const RefHash2KeysTableBucketElem<TVal>* findIt = findBucketElem(key1, key2, hashVal);
00144     return (findIt != 0);
00145 }
00146 
00147 template <class TVal, class THasher>
00148 void RefHash2KeysTableOf<TVal, THasher>::
00149 removeKey(const void* const key1, const int key2)
00150 {
00151     // Hash the key
00152     XMLSize_t hashVal = fHasher.getHashVal(key1, fHashModulus);
00153     assert(hashVal < fHashModulus);
00154 
00155     //
00156     //  Search the given bucket for this key. Keep up with the previous
00157     //  element so we can patch around it.
00158     //
00159     RefHash2KeysTableBucketElem<TVal>* curElem = fBucketList[hashVal];
00160     RefHash2KeysTableBucketElem<TVal>* lastElem = 0;
00161 
00162     while (curElem)
00163     {
00164         if((key2==curElem->fKey2) && (fHasher.equals(key1, curElem->fKey1)))
00165         {
00166             if (!lastElem)
00167             {
00168                 // It was the first in the bucket
00169                 fBucketList[hashVal] = curElem->fNext;
00170             }
00171             else
00172             {
00173                 // Patch around the current element
00174                 lastElem->fNext = curElem->fNext;
00175             }
00176 
00177             // If we adopted the elements, then delete the data
00178             if (fAdoptedElems)
00179                 delete curElem->fData;
00180 
00181             // Delete the current element
00182             // delete curElem;
00183             // destructor is empty...
00184             // curElem->~RefHash2KeysTableBucketElem();
00185             fMemoryManager->deallocate(curElem);
00186             fCount--;
00187             return;
00188         }
00189 
00190         // Move both pointers upwards
00191         lastElem = curElem;
00192         curElem = curElem->fNext;
00193     }
00194 
00195     // We never found that key
00196     ThrowXMLwithMemMgr(NoSuchElementException, XMLExcepts::HshTbl_NoSuchKeyExists, fMemoryManager);
00197 }
00198 
00199 template <class TVal, class THasher>
00200 void RefHash2KeysTableOf<TVal, THasher>::
00201 removeKey(const void* const key1)
00202 {
00203     // Hash the key
00204     XMLSize_t hashVal = fHasher.getHashVal(key1, fHashModulus);
00205     assert(hashVal < fHashModulus);
00206 
00207     //
00208     //  Search the given bucket for this key. Keep up with the previous
00209     //  element so we can patch around it.
00210     //
00211     RefHash2KeysTableBucketElem<TVal>* curElem = fBucketList[hashVal];
00212     RefHash2KeysTableBucketElem<TVal>* lastElem = 0;
00213 
00214     while (curElem)
00215     {
00216         if(fHasher.equals(key1, curElem->fKey1))
00217         {
00218             if (!lastElem)
00219             {
00220                 // It was the first in the bucket
00221                 fBucketList[hashVal] = curElem->fNext;
00222             }
00223             else
00224             {
00225                 // Patch around the current element
00226                 lastElem->fNext = curElem->fNext;
00227             }
00228 
00229             // If we adopted the elements, then delete the data
00230             if (fAdoptedElems)
00231                 delete curElem->fData;
00232 
00233             RefHash2KeysTableBucketElem<TVal>* toBeDeleted=curElem;
00234             curElem = curElem->fNext;
00235 
00236             // Delete the current element
00237             // delete curElem;
00238             // destructor is empty...
00239             // curElem->~RefHash2KeysTableBucketElem();
00240             fMemoryManager->deallocate(toBeDeleted);
00241             fCount--;
00242         }
00243         else
00244         {
00245             // Move both pointers upwards
00246             lastElem = curElem;
00247             curElem = curElem->fNext;
00248         }
00249     }
00250 }
00251 
00252 template <class TVal, class THasher>
00253 void RefHash2KeysTableOf<TVal, THasher>::removeAll()
00254 {
00255     if(isEmpty())
00256         return;
00257 
00258     // Clean up the buckets first
00259     for (XMLSize_t buckInd = 0; buckInd < fHashModulus; buckInd++)
00260     {
00261         // Get the bucket list head for this entry
00262         RefHash2KeysTableBucketElem<TVal>* curElem = fBucketList[buckInd];
00263         RefHash2KeysTableBucketElem<TVal>* nextElem;
00264         while (curElem)
00265         {
00266             // Save the next element before we hose this one
00267             nextElem = curElem->fNext;
00268 
00269             // If we adopted the data, then delete it too
00270             //    (Note:  the userdata hash table instance has data type of void *.
00271             //    This will generate compiler warnings here on some platforms, but they
00272             //    can be ignored since fAdoptedElements is false.
00273             if (fAdoptedElems)
00274                 delete curElem->fData;
00275 
00276             // Then delete the current element and move forward
00277             // destructor is empty...
00278             // curElem->~RefHash2KeysTableBucketElem();
00279             fMemoryManager->deallocate(curElem);
00280             curElem = nextElem;
00281         }
00282 
00283         // Clean out this entry
00284         fBucketList[buckInd] = 0;
00285     }
00286     fCount=0;
00287 }
00288 
00289 // this function transfer the data from key1 to key2
00290 template <class TVal, class THasher>
00291 void RefHash2KeysTableOf<TVal, THasher>::transferElement(const void* const key1, void* key2)
00292 {
00293     // Hash the key
00294     XMLSize_t hashVal = fHasher.getHashVal(key1, fHashModulus);
00295     assert(hashVal < fHashModulus);
00296 
00297     //
00298     //  Search the given bucket for this key. Keep up with the previous
00299     //  element so we can patch around it.
00300     //
00301     RefHash2KeysTableBucketElem<TVal>* curElem = fBucketList[hashVal];
00302     RefHash2KeysTableBucketElem<TVal>* lastElem = 0;
00303 
00304     while (curElem)
00305     {
00306         // if this element has the same primary key, remove it and add it using the new primary key
00307         if(fHasher.equals(key1, curElem->fKey1))
00308         {
00309             if (!lastElem)
00310             {
00311                 // It was the first in the bucket
00312                 fBucketList[hashVal] = curElem->fNext;
00313             }
00314             else
00315             {
00316                 // Patch around the current element
00317                 lastElem->fNext = curElem->fNext;
00318             }
00319 
00320             // this code comes from put(), but it doesn't update fCount
00321             XMLSize_t hashVal2;
00322             RefHash2KeysTableBucketElem<TVal>* newBucket = findBucketElem(key2, curElem->fKey2, hashVal2);
00323             if (newBucket)
00324             {
00325                 if (fAdoptedElems)
00326                     delete newBucket->fData;
00327                 newBucket->fData = curElem->fData;
00328                 newBucket->fKey1 = key2;
00329                 newBucket->fKey2 = curElem->fKey2;
00330             }
00331              else
00332             {
00333                 newBucket =
00334                     new (fMemoryManager->allocate(sizeof(RefHash2KeysTableBucketElem<TVal>)))
00335                     RefHash2KeysTableBucketElem<TVal>(key2, curElem->fKey2, curElem->fData, fBucketList[hashVal2]);
00336                 fBucketList[hashVal2] = newBucket;
00337             }
00338 
00339             RefHash2KeysTableBucketElem<TVal>* elemToDelete = curElem;
00340 
00341             // Update just curElem; lastElem must stay the same
00342             curElem = curElem->fNext;
00343 
00344             // Delete the current element
00345             // delete elemToDelete;
00346             // destructor is empty...
00347             // curElem->~RefHash2KeysTableBucketElem();
00348             fMemoryManager->deallocate(elemToDelete);
00349         }
00350         else
00351         {
00352             // Move both pointers upwards
00353             lastElem = curElem;
00354             curElem = curElem->fNext;
00355         }
00356     }
00357 }
00358 
00359 
00360 
00361 // ---------------------------------------------------------------------------
00362 //  RefHash2KeysTableOf: Getters
00363 // ---------------------------------------------------------------------------
00364 template <class TVal, class THasher>
00365 TVal* RefHash2KeysTableOf<TVal, THasher>::get(const void* const key1, const int key2)
00366 {
00367     XMLSize_t hashVal;
00368     RefHash2KeysTableBucketElem<TVal>* findIt = findBucketElem(key1, key2, hashVal);
00369     if (!findIt)
00370         return 0;
00371     return findIt->fData;
00372 }
00373 
00374 template <class TVal, class THasher>
00375 const TVal* RefHash2KeysTableOf<TVal, THasher>::
00376 get(const void* const key1, const int key2) const
00377 {
00378     XMLSize_t hashVal;
00379     const RefHash2KeysTableBucketElem<TVal>* findIt = findBucketElem(key1, key2, hashVal);
00380     if (!findIt)
00381         return 0;
00382     return findIt->fData;
00383 }
00384 
00385 template <class TVal, class THasher>
00386 MemoryManager* RefHash2KeysTableOf<TVal, THasher>::getMemoryManager() const
00387 {
00388     return fMemoryManager;
00389 }
00390 
00391 template <class TVal, class THasher>
00392 XMLSize_t RefHash2KeysTableOf<TVal, THasher>::getHashModulus() const
00393 {
00394     return fHashModulus;
00395 }
00396 
00397 // ---------------------------------------------------------------------------
00398 //  RefHash2KeysTableOf: Putters
00399 // ---------------------------------------------------------------------------
00400 template <class TVal, class THasher>
00401 void RefHash2KeysTableOf<TVal, THasher>::put(void* key1, int key2, TVal* const valueToAdopt)
00402 {
00403     // Apply 4 load factor to find threshold.
00404     XMLSize_t threshold = fHashModulus * 4;
00405 
00406     // If we've grown too big, expand the table and rehash.
00407     if (fCount >= threshold)
00408         rehash();
00409 
00410     // First see if the key exists already
00411     XMLSize_t hashVal;
00412     RefHash2KeysTableBucketElem<TVal>* newBucket = findBucketElem(key1, key2, hashVal);
00413 
00414     //
00415     //  If so,then update its value. If not, then we need to add it to
00416     //  the right bucket
00417     //
00418     if (newBucket)
00419     {
00420         if (fAdoptedElems)
00421             delete newBucket->fData;
00422         newBucket->fData = valueToAdopt;
00423         newBucket->fKey1 = key1;
00424         newBucket->fKey2 = key2;
00425     }
00426      else
00427     {
00428         newBucket =
00429             new (fMemoryManager->allocate(sizeof(RefHash2KeysTableBucketElem<TVal>)))
00430             RefHash2KeysTableBucketElem<TVal>(key1, key2, valueToAdopt, fBucketList[hashVal]);
00431         fBucketList[hashVal] = newBucket;
00432         fCount++;
00433     }
00434 }
00435 
00436 
00437 
00438 // ---------------------------------------------------------------------------
00439 //  RefHash2KeysTableOf: Private methods
00440 // ---------------------------------------------------------------------------
00441 template <class TVal, class THasher>
00442 inline RefHash2KeysTableBucketElem<TVal>* RefHash2KeysTableOf<TVal, THasher>::
00443 findBucketElem(const void* const key1, const int key2, XMLSize_t& hashVal)
00444 {
00445     // Hash the key
00446     hashVal = fHasher.getHashVal(key1, fHashModulus);
00447     assert(hashVal < fHashModulus);
00448 
00449     // Search that bucket for the key
00450     RefHash2KeysTableBucketElem<TVal>* curElem = fBucketList[hashVal];
00451     while (curElem)
00452     {
00453         if((key2==curElem->fKey2) && (fHasher.equals(key1, curElem->fKey1)))
00454             return curElem;
00455 
00456         curElem = curElem->fNext;
00457     }
00458     return 0;
00459 }
00460 
00461 template <class TVal, class THasher>
00462 inline const RefHash2KeysTableBucketElem<TVal>* RefHash2KeysTableOf<TVal, THasher>::
00463 findBucketElem(const void* const key1, const int key2, XMLSize_t& hashVal) const
00464 {
00465     // Hash the key
00466     hashVal = fHasher.getHashVal(key1, fHashModulus);
00467     assert(hashVal < fHashModulus);
00468 
00469     // Search that bucket for the key
00470     const RefHash2KeysTableBucketElem<TVal>* curElem = fBucketList[hashVal];
00471     while (curElem)
00472     {
00473         if((key2==curElem->fKey2) && (fHasher.equals(key1, curElem->fKey1)))
00474             return curElem;
00475 
00476         curElem = curElem->fNext;
00477     }
00478     return 0;
00479 }
00480 
00481 
00482 template <class TVal, class THasher>
00483 void RefHash2KeysTableOf<TVal, THasher>::
00484 rehash()
00485 {
00486     const XMLSize_t newMod = (fHashModulus * 8)+1;
00487 
00488     RefHash2KeysTableBucketElem<TVal>** newBucketList =
00489         (RefHash2KeysTableBucketElem<TVal>**) fMemoryManager->allocate
00490     (
00491         newMod * sizeof(RefHash2KeysTableBucketElem<TVal>*)
00492     );//new RefHash2KeysTableBucketElem<TVal>*[fHashModulus];
00493 
00494     // Make sure the new bucket list is destroyed if an
00495     // exception is thrown.
00496     ArrayJanitor<RefHash2KeysTableBucketElem<TVal>*>  guard(newBucketList, fMemoryManager);
00497 
00498     memset(newBucketList, 0, newMod * sizeof(newBucketList[0]));
00499 
00500     // Rehash all existing entries.
00501     for (XMLSize_t index = 0; index < fHashModulus; index++)
00502     {
00503         // Get the bucket list head for this entry
00504         RefHash2KeysTableBucketElem<TVal>* curElem = fBucketList[index];
00505         while (curElem)
00506         {
00507             // Save the next element before we detach this one
00508             RefHash2KeysTableBucketElem<TVal>* nextElem = curElem->fNext;
00509 
00510             const XMLSize_t hashVal = fHasher.getHashVal(curElem->fKey1, newMod);
00511             assert(hashVal < newMod);
00512 
00513             RefHash2KeysTableBucketElem<TVal>* newHeadElem = newBucketList[hashVal];
00514 
00515             // Insert at the start of this bucket's list.
00516             curElem->fNext = newHeadElem;
00517             newBucketList[hashVal] = curElem;
00518 
00519             curElem = nextElem;
00520         }
00521     }
00522 
00523     RefHash2KeysTableBucketElem<TVal>** const oldBucketList = fBucketList;
00524 
00525     // Everything is OK at this point, so update the
00526     // member variables.
00527     fBucketList = guard.release();
00528     fHashModulus = newMod;
00529 
00530     // Delete the old bucket list.
00531     fMemoryManager->deallocate(oldBucketList);//delete[] oldBucketList;
00532 
00533 }
00534 
00535 
00536 
00537 // ---------------------------------------------------------------------------
00538 //  RefHash2KeysTableOfEnumerator: Constructors and Destructor
00539 // ---------------------------------------------------------------------------
00540 template <class TVal, class THasher>
00541 RefHash2KeysTableOfEnumerator<TVal, THasher>::
00542 RefHash2KeysTableOfEnumerator(RefHash2KeysTableOf<TVal, THasher>* const toEnum
00543                               , const bool adopt
00544                               , MemoryManager* const manager)
00545     : fAdopted(adopt), fCurElem(0), fCurHash((XMLSize_t)-1), fToEnum(toEnum)
00546     , fMemoryManager(manager)
00547     , fLockPrimaryKey(0)
00548 {
00549     if (!toEnum)
00550         ThrowXMLwithMemMgr(NullPointerException, XMLExcepts::CPtr_PointerIsZero, fMemoryManager);
00551 
00552     //
00553     //  Find the next available bucket element in the hash table. If it
00554     //  comes back zero, that just means the table is empty.
00555     //
00556     //  Note that the -1 in the current hash tells it to start
00557     //  from the beginning.
00558     //
00559     findNext();
00560 }
00561 
00562 template <class TVal, class THasher>
00563 RefHash2KeysTableOfEnumerator<TVal, THasher>::~RefHash2KeysTableOfEnumerator()
00564 {
00565     if (fAdopted)
00566         delete fToEnum;
00567 }
00568 
00569 
00570 // ---------------------------------------------------------------------------
00571 //  RefHash2KeysTableOfEnumerator: Enum interface
00572 // ---------------------------------------------------------------------------
00573 template <class TVal, class THasher>
00574 bool RefHash2KeysTableOfEnumerator<TVal, THasher>::hasMoreElements() const
00575 {
00576     //
00577     //  If our current has is at the max and there are no more elements
00578     //  in the current bucket, then no more elements.
00579     //
00580     if (!fCurElem && (fCurHash == fToEnum->fHashModulus))
00581         return false;
00582     return true;
00583 }
00584 
00585 template <class TVal, class THasher>
00586 TVal& RefHash2KeysTableOfEnumerator<TVal, THasher>::nextElement()
00587 {
00588     // Make sure we have an element to return
00589     if (!hasMoreElements())
00590         ThrowXMLwithMemMgr(NoSuchElementException, XMLExcepts::Enum_NoMoreElements, fMemoryManager);
00591 
00592     //
00593     //  Save the current element, then move up to the next one for the
00594     //  next time around.
00595     //
00596     RefHash2KeysTableBucketElem<TVal>* saveElem = fCurElem;
00597     findNext();
00598 
00599     return *saveElem->fData;
00600 }
00601 
00602 template <class TVal, class THasher>
00603 void RefHash2KeysTableOfEnumerator<TVal, THasher>::nextElementKey(void*& retKey1, int& retKey2)
00604 {
00605     // Make sure we have an element to return
00606     if (!hasMoreElements())
00607         ThrowXMLwithMemMgr(NoSuchElementException, XMLExcepts::Enum_NoMoreElements, fMemoryManager);
00608 
00609     //
00610     //  Save the current element, then move up to the next one for the
00611     //  next time around.
00612     //
00613     RefHash2KeysTableBucketElem<TVal>* saveElem = fCurElem;
00614     findNext();
00615 
00616     retKey1 = saveElem->fKey1;
00617     retKey2 = saveElem->fKey2;
00618 
00619     return;
00620 }
00621 
00622 template <class TVal, class THasher>
00623 void RefHash2KeysTableOfEnumerator<TVal, THasher>::Reset()
00624 {
00625     if(fLockPrimaryKey)
00626         fCurHash=fToEnum->fHasher.getHashVal(fLockPrimaryKey, fToEnum->fHashModulus);
00627     else
00628         fCurHash = (XMLSize_t)-1;
00629 
00630     fCurElem = 0;
00631     findNext();
00632 }
00633 
00634 
00635 template <class TVal, class THasher>
00636 void RefHash2KeysTableOfEnumerator<TVal, THasher>::setPrimaryKey(const void* key)
00637 {
00638     fLockPrimaryKey=key;
00639     Reset();
00640 }
00641 
00642 // ---------------------------------------------------------------------------
00643 //  RefHash2KeysTableOfEnumerator: Private helper methods
00644 // ---------------------------------------------------------------------------
00645 template <class TVal, class THasher>
00646 void RefHash2KeysTableOfEnumerator<TVal, THasher>::findNext()
00647 {
00648     //  Code to execute if we have to return only values with the primary key
00649     if(fLockPrimaryKey)
00650     {
00651         if(!fCurElem)
00652             fCurElem = fToEnum->fBucketList[fCurHash];
00653         else
00654             fCurElem = fCurElem->fNext;
00655         while (fCurElem && (!fToEnum->fHasher.equals(fLockPrimaryKey, fCurElem->fKey1)))
00656             fCurElem = fCurElem->fNext;
00657         // if we didn't found it, make so hasMoreElements() returns false
00658         if(!fCurElem)
00659             fCurHash = fToEnum->fHashModulus;
00660         return;
00661     }
00662     //
00663     //  If there is a current element, move to its next element. If this
00664     //  hits the end of the bucket, the next block will handle the rest.
00665     //
00666     if (fCurElem)
00667         fCurElem = fCurElem->fNext;
00668 
00669     //
00670     //  If the current element is null, then we have to move up to the
00671     //  next hash value. If that is the hash modulus, then we cannot
00672     //  go further.
00673     //
00674     if (!fCurElem)
00675     {
00676         fCurHash++;
00677         if (fCurHash == fToEnum->fHashModulus)
00678             return;
00679 
00680         // Else find the next non-empty bucket
00681         while (fToEnum->fBucketList[fCurHash]==0)
00682         {
00683             // Bump to the next hash value. If we max out return
00684             fCurHash++;
00685             if (fCurHash == fToEnum->fHashModulus)
00686                 return;
00687         }
00688         fCurElem = fToEnum->fBucketList[fCurHash];
00689     }
00690 }
00691 
00692 XERCES_CPP_NAMESPACE_END