Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 10:27:25

0001 /*
0002  * Licensed to the Apache Software Foundation (ASF) under one or more
0003  * contributor license agreements.  See the NOTICE file distributed with
0004  * this work for additional information regarding copyright ownership.
0005  * The ASF licenses this file to You under the Apache License, Version 2.0
0006  * (the "License"); you may not use this file except in compliance with
0007  * the License.  You may obtain a copy of the License at
0008  *
0009  *      http://www.apache.org/licenses/LICENSE-2.0
0010  *
0011  * Unless required by applicable law or agreed to in writing, software
0012  * distributed under the License is distributed on an "AS IS" BASIS,
0013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014  * See the License for the specific language governing permissions and
0015  * limitations under the License.
0016  */
0017 
0018 /*
0019  * $Id$
0020  */
0021 
0022 
0023 // ---------------------------------------------------------------------------
0024 //  Include
0025 // ---------------------------------------------------------------------------
0026 #if defined(XERCES_TMPLSINC)
0027 #include <xercesc/util/RefHashTableOf.hpp>
0028 #endif
0029 
0030 #include <xercesc/util/Janitor.hpp>
0031 #include <xercesc/util/XMLString.hpp>
0032 #include <xercesc/util/NullPointerException.hpp>
0033 #include <new>
0034 
0035 XERCES_CPP_NAMESPACE_BEGIN
0036 
0037 // ---------------------------------------------------------------------------
0038 //  RefHashTableOf: Constructors and Destructor
0039 // ---------------------------------------------------------------------------
0040 template <class TVal, class THasher>
0041 RefHashTableOf<TVal, THasher>::RefHashTableOf(
0042   const XMLSize_t modulus,
0043   MemoryManager* const manager)
0044 
0045     : fMemoryManager(manager)
0046     , fAdoptedElems(true)
0047     , fBucketList(0)
0048     , fHashModulus(modulus)
0049     , fInitialModulus(modulus)
0050     , fCount(0)
0051 {
0052     initialize(modulus);
0053 }
0054 
0055 template <class TVal, class THasher>
0056 RefHashTableOf<TVal, THasher>::RefHashTableOf(
0057   const XMLSize_t modulus,
0058   const THasher& hasher,
0059   MemoryManager* const manager)
0060 
0061     : fMemoryManager(manager)
0062     , fAdoptedElems(true)
0063     , fBucketList(0)
0064     , fHashModulus(modulus)
0065     , fInitialModulus(modulus)
0066     , fCount(0)
0067     , fHasher (hasher)
0068 {
0069     initialize(modulus);
0070 }
0071 
0072 template <class TVal, class THasher>
0073 RefHashTableOf<TVal, THasher>::RefHashTableOf(
0074   const XMLSize_t modulus,
0075   const bool adoptElems,
0076   MemoryManager* const manager)
0077 
0078     : fMemoryManager(manager)
0079     , fAdoptedElems(adoptElems)
0080     , fBucketList(0)
0081     , fHashModulus(modulus)
0082     , fInitialModulus(modulus)
0083     , fCount(0)
0084 
0085 {
0086     initialize(modulus);
0087 }
0088 
0089 template <class TVal, class THasher>
0090 RefHashTableOf<TVal, THasher>::RefHashTableOf(
0091   const XMLSize_t modulus,
0092   const bool adoptElems,
0093   const THasher& hasher,
0094   MemoryManager* const manager)
0095 
0096     : fMemoryManager(manager)
0097     , fAdoptedElems(adoptElems)
0098     , fBucketList(0)
0099     , fHashModulus(modulus)
0100     , fInitialModulus(modulus)
0101     , fCount(0)
0102     , fHasher (hasher)
0103 {
0104     initialize(modulus);
0105 }
0106 
0107 template <class TVal, class THasher>
0108 void RefHashTableOf<TVal, THasher>::initialize(const XMLSize_t modulus)
0109 {
0110     if (modulus == 0)
0111         ThrowXMLwithMemMgr(IllegalArgumentException, XMLExcepts::HshTbl_ZeroModulus, fMemoryManager);
0112 
0113     // Allocate the bucket list and zero them
0114     fBucketList = (RefHashTableBucketElem<TVal>**) fMemoryManager->allocate
0115     (
0116         fHashModulus * sizeof(RefHashTableBucketElem<TVal>*)
0117     );
0118     for (XMLSize_t index = 0; index < fHashModulus; index++)
0119         fBucketList[index] = 0;
0120 }
0121 
0122 template <class TVal, class THasher>
0123 RefHashTableOf<TVal, THasher>::~RefHashTableOf()
0124 {
0125     cleanup();
0126 }
0127 
0128 
0129 // ---------------------------------------------------------------------------
0130 //  RefHashTableOf: Element management
0131 // ---------------------------------------------------------------------------
0132 template <class TVal, class THasher>
0133 inline bool RefHashTableOf<TVal, THasher>::isEmpty() const
0134 {
0135     return fCount==0;
0136 }
0137 
0138 template <class TVal, class THasher>
0139 inline bool RefHashTableOf<TVal, THasher>::containsKey(const void* const key) const
0140 {
0141     XMLSize_t hashVal;
0142     const RefHashTableBucketElem<TVal>* findIt = findBucketElem(key, hashVal);
0143     return (findIt != 0);
0144 }
0145 
0146 template <class TVal, class THasher>
0147 void RefHashTableOf<TVal, THasher>::
0148 removeKey(const void* const key)
0149 {
0150     // Hash the key
0151     XMLSize_t hashVal = fHasher.getHashVal(key, fHashModulus);
0152 
0153     //
0154     //  Search the given bucket for this key. Keep up with the previous
0155     //  element so we can patch around it.
0156     //
0157     RefHashTableBucketElem<TVal>* curElem = fBucketList[hashVal];
0158     RefHashTableBucketElem<TVal>* lastElem = 0;
0159 
0160     while (curElem)
0161     {
0162         if (fHasher.equals(key, curElem->fKey))
0163         {
0164             if (!lastElem)
0165             {
0166                 // It was the first in the bucket
0167                 fBucketList[hashVal] = curElem->fNext;
0168             }
0169              else
0170             {
0171                 // Patch around the current element
0172                 lastElem->fNext = curElem->fNext;
0173             }
0174 
0175             // If we adopted the data, then delete it too
0176             //    (Note:  the userdata hash table instance has data type of void *.
0177             //    This will generate compiler warnings here on some platforms, but they
0178             //    can be ignored since fAdoptedElements is false.
0179             if (fAdoptedElems)
0180                 delete curElem->fData;
0181 
0182             // Then delete the current element and move forward
0183             // delete curElem;
0184             // destructor doesn't do anything...
0185             fMemoryManager->deallocate(curElem);
0186 
0187             fCount--;
0188 
0189             return;
0190         }
0191 
0192         // Move both pointers upwards
0193         lastElem = curElem;
0194         curElem = curElem->fNext;
0195     }
0196 
0197     // We never found that key
0198     ThrowXMLwithMemMgr(NoSuchElementException, XMLExcepts::HshTbl_NoSuchKeyExists, fMemoryManager);
0199 }
0200 
0201 template <class TVal, class THasher>
0202 void RefHashTableOf<TVal, THasher>::removeAll()
0203 {
0204     if(isEmpty())
0205         return;
0206 
0207     // Clean up the buckets first
0208     for (XMLSize_t buckInd = 0; buckInd < fHashModulus; buckInd++)
0209     {
0210         // Get the bucket list head for this entry
0211         RefHashTableBucketElem<TVal>* curElem = fBucketList[buckInd];
0212         RefHashTableBucketElem<TVal>* nextElem;
0213         while (curElem)
0214         {
0215             // Save the next element before we hose this one
0216             nextElem = curElem->fNext;
0217 
0218             // If we adopted the data, then delete it too
0219             //    (Note:  the userdata hash table instance has data type of void *.
0220             //    This will generate compiler warnings here on some platforms, but they
0221             //    can be ignored since fAdoptedElements is false.
0222             if (fAdoptedElems)
0223                 delete curElem->fData;
0224 
0225             // Then delete the current element and move forward
0226              // delete curElem;
0227             // destructor doesn't do anything...
0228             // curElem->~RefHashTableBucketElem();
0229             fMemoryManager->deallocate(curElem);
0230             curElem = nextElem;
0231         }
0232 
0233         // Clean out this entry
0234         fBucketList[buckInd] = 0;
0235     }
0236 
0237     fCount = 0;
0238 }
0239 
0240 // This method returns the data associated with a key. The key entry is deleted. The caller
0241 // now owns the returned data (case of hashtable adopting the data).
0242 // This function is called by transferElement so that the undeleted data can be transferred
0243 // to a new key which will own that data.
0244 template <class TVal, class THasher> TVal* RefHashTableOf<TVal, THasher>::
0245 orphanKey(const void* const key)
0246 {
0247     // Hash the key
0248     TVal* retVal = 0;
0249     XMLSize_t hashVal = fHasher.getHashVal(key, fHashModulus);
0250 
0251     //
0252     //  Search the given bucket for this key. Keep up with the previous
0253     //  element so we can patch around it.
0254     //
0255     RefHashTableBucketElem<TVal>* curElem = fBucketList[hashVal];
0256     RefHashTableBucketElem<TVal>* lastElem = 0;
0257 
0258     while (curElem)
0259     {
0260         if (fHasher.equals(key, curElem->fKey))
0261         {
0262             if (!lastElem)
0263             {
0264                 // It was the first in the bucket
0265                 fBucketList[hashVal] = curElem->fNext;
0266             }
0267             else
0268             {
0269                 // Patch around the current element
0270                 lastElem->fNext = curElem->fNext;
0271             }
0272 
0273             retVal = curElem->fData;
0274 
0275             // Delete the current element
0276             // delete curElem;
0277             // destructor doesn't do anything...
0278             // curElem->~RefHashTableBucketElem();
0279             fMemoryManager->deallocate(curElem);
0280             break;
0281         }
0282 
0283         // Move both pointers upwards
0284         lastElem = curElem;
0285         curElem = curElem->fNext;
0286     }
0287 
0288     // We never found that key
0289     if (!retVal)
0290         ThrowXMLwithMemMgr(NoSuchElementException, XMLExcepts::HshTbl_NoSuchKeyExists, fMemoryManager);
0291 
0292     return retVal;
0293 }
0294 
0295 //
0296 // cleanup():
0297 //   similar to destructor
0298 //   called to cleanup the memory, in case destructor cannot be called
0299 //
0300 template <class TVal, class THasher>
0301 void RefHashTableOf<TVal, THasher>::cleanup()
0302 {
0303     removeAll();
0304 
0305     // Then delete the bucket list & hasher
0306     fMemoryManager->deallocate(fBucketList);
0307     fBucketList = 0;
0308 }
0309 
0310 //
0311 // reinitialize():
0312 //   similar to constructor
0313 //   called to re-construct the fElemList from scratch again
0314 //
0315 template <class TVal, class THasher>
0316 void RefHashTableOf<TVal, THasher>::reinitialize(const THasher& hasher)
0317 {
0318     if (fBucketList)
0319         cleanup();
0320 
0321     fHasher = hasher;
0322 
0323     fHashModulus = fInitialModulus;
0324     initialize(fHashModulus);
0325 }
0326 
0327 
0328 
0329 // this function transfer the data from key1 to key2
0330 // this is equivalent to calling
0331 //  1.  get(key1) to retrieve the data,
0332 //  2.  removeKey(key1),
0333 //  3.  and then put(key2, data)
0334 // except that the data is not deleted in "removeKey" even it is adopted so that it
0335 // can be transferred to key2.
0336 // whatever key2 has originally will be purged (if adopted)
0337 template <class TVal, class THasher>
0338 inline void RefHashTableOf<TVal, THasher>::transferElement(const void* const key1, void* key2)
0339 {
0340     put(key2, orphanKey(key1));
0341 }
0342 
0343 
0344 // ---------------------------------------------------------------------------
0345 //  RefHashTableOf: Getters
0346 // ---------------------------------------------------------------------------
0347 template <class TVal, class THasher>
0348 inline TVal* RefHashTableOf<TVal, THasher>::get(const void* const key)
0349 {
0350     XMLSize_t hashVal;
0351     RefHashTableBucketElem<TVal>* findIt = findBucketElem(key, hashVal);
0352     return findIt ? findIt->fData : 0;
0353 }
0354 
0355 template <class TVal, class THasher>
0356 inline const TVal* RefHashTableOf<TVal, THasher>::
0357 get(const void* const key) const
0358 {
0359     XMLSize_t hashVal;
0360     const RefHashTableBucketElem<TVal>* findIt = findBucketElem(key, hashVal);
0361     return findIt ? findIt->fData : 0;
0362 }
0363 
0364 template <class TVal, class THasher>
0365 inline MemoryManager* RefHashTableOf<TVal, THasher>::getMemoryManager() const
0366 {
0367     return fMemoryManager;
0368 }
0369 
0370 template <class TVal, class THasher>
0371 inline XMLSize_t RefHashTableOf<TVal, THasher>::getHashModulus() const
0372 {
0373     return fHashModulus;
0374 }
0375 
0376 template <class TVal, class THasher>
0377 inline XMLSize_t RefHashTableOf<TVal, THasher>::getCount() const
0378 {
0379     return fCount;
0380 }
0381 
0382 // ---------------------------------------------------------------------------
0383 //  RefHashTableOf: Getters
0384 // ---------------------------------------------------------------------------
0385 template <class TVal, class THasher>
0386 inline void RefHashTableOf<TVal, THasher>::setAdoptElements(const bool aValue)
0387 {
0388     fAdoptedElems = aValue;
0389 }
0390 
0391 // ---------------------------------------------------------------------------
0392 //  RefHashTableOf: Putters
0393 // ---------------------------------------------------------------------------
0394 template <class TVal, class THasher>
0395 void RefHashTableOf<TVal, THasher>::put(void* key, TVal* const valueToAdopt)
0396 {
0397     // Apply 0.75 load factor to find threshold.
0398     XMLSize_t threshold = fHashModulus * 3 / 4;
0399 
0400     // If we've grown too big, expand the table and rehash.
0401     if (fCount >= threshold)
0402         rehash();
0403 
0404     // First see if the key exists already
0405     XMLSize_t hashVal;
0406     RefHashTableBucketElem<TVal>* newBucket = findBucketElem(key, hashVal);
0407 
0408     //
0409     //  If so,then update its value. If not, then we need to add it to
0410     //  the right bucket
0411     //
0412     if (newBucket)
0413     {
0414         if (fAdoptedElems)
0415             delete newBucket->fData;
0416         newBucket->fData = valueToAdopt;
0417         newBucket->fKey = key;
0418     }
0419     else
0420     {
0421         newBucket =
0422              new (fMemoryManager->allocate(sizeof(RefHashTableBucketElem<TVal>)))
0423              RefHashTableBucketElem<TVal>(key, valueToAdopt, fBucketList[hashVal]);
0424         fBucketList[hashVal] = newBucket;
0425         fCount++;
0426     }
0427 }
0428 
0429 
0430 
0431 // ---------------------------------------------------------------------------
0432 //  RefHashTableOf: Private methods
0433 // ---------------------------------------------------------------------------
0434 template <class TVal, class THasher>
0435 void RefHashTableOf<TVal, THasher>::rehash()
0436 {
0437     const XMLSize_t newMod = (fHashModulus * 2) + 1;
0438 
0439     RefHashTableBucketElem<TVal>** newBucketList =
0440         (RefHashTableBucketElem<TVal>**) fMemoryManager->allocate
0441     (
0442         newMod * sizeof(RefHashTableBucketElem<TVal>*)
0443     );
0444 
0445     // Make sure the new bucket list is destroyed if an
0446     // exception is thrown.
0447     ArrayJanitor<RefHashTableBucketElem<TVal>*>  guard(newBucketList, fMemoryManager);
0448 
0449     memset(newBucketList, 0, newMod * sizeof(newBucketList[0]));
0450 
0451 
0452     // Rehash all existing entries.
0453     for (XMLSize_t index = 0; index < fHashModulus; index++)
0454     {
0455         // Get the bucket list head for this entry
0456         RefHashTableBucketElem<TVal>* curElem = fBucketList[index];
0457 
0458         while (curElem)
0459         {
0460             // Save the next element before we detach this one
0461             RefHashTableBucketElem<TVal>* const nextElem = curElem->fNext;
0462 
0463             const XMLSize_t hashVal = fHasher.getHashVal(curElem->fKey, newMod);
0464 
0465             RefHashTableBucketElem<TVal>* const newHeadElem = newBucketList[hashVal];
0466 
0467             // Insert at the start of this bucket's list.
0468             curElem->fNext = newHeadElem;
0469             newBucketList[hashVal] = curElem;
0470 
0471             curElem = nextElem;
0472         }
0473     }
0474 
0475     RefHashTableBucketElem<TVal>** const oldBucketList = fBucketList;
0476 
0477     // Everything is OK at this point, so update the
0478     // member variables.
0479     fBucketList = guard.release();
0480     fHashModulus = newMod;
0481 
0482     // Delete the old bucket list.
0483     fMemoryManager->deallocate(oldBucketList);//delete[] oldBucketList;
0484 
0485 }
0486 
0487 template <class TVal, class THasher>
0488 inline RefHashTableBucketElem<TVal>* RefHashTableOf<TVal, THasher>::
0489 findBucketElem(const void* const key, XMLSize_t& hashVal)
0490 {
0491     // Hash the key
0492     hashVal = fHasher.getHashVal(key, fHashModulus);
0493 
0494     // Search that bucket for the key
0495     RefHashTableBucketElem<TVal>* curElem = fBucketList[hashVal];
0496     while (curElem)
0497     {
0498         if (fHasher.equals(key, curElem->fKey))
0499             return curElem;
0500 
0501         curElem = curElem->fNext;
0502     }
0503     return 0;
0504 }
0505 
0506 template <class TVal, class THasher>
0507 inline const RefHashTableBucketElem<TVal>* RefHashTableOf<TVal, THasher>::
0508 findBucketElem(const void* const key, XMLSize_t& hashVal) const
0509 {
0510     // Hash the key
0511     hashVal = fHasher.getHashVal(key, fHashModulus);
0512 
0513     // Search that bucket for the key
0514     const RefHashTableBucketElem<TVal>* curElem = fBucketList[hashVal];
0515     while (curElem)
0516     {
0517         if (fHasher.equals(key, curElem->fKey))
0518             return curElem;
0519 
0520         curElem = curElem->fNext;
0521     }
0522     return 0;
0523 }
0524 
0525 
0526 // ---------------------------------------------------------------------------
0527 //  RefHashTableOfEnumerator: Constructors and Destructor
0528 // ---------------------------------------------------------------------------
0529 template <class TVal, class THasher> RefHashTableOfEnumerator<TVal, THasher>::
0530 RefHashTableOfEnumerator(RefHashTableOf<TVal, THasher>* const toEnum
0531                          , const bool adopt
0532                          , MemoryManager* const manager)
0533     : fAdopted(adopt), fCurElem(0), fCurHash((XMLSize_t)-1), fToEnum(toEnum)
0534     , fMemoryManager(manager)
0535 {
0536     if (!toEnum)
0537         ThrowXMLwithMemMgr(NullPointerException, XMLExcepts::CPtr_PointerIsZero, fMemoryManager);
0538 
0539     //
0540     //  Find the next available bucket element in the hash table. If it
0541     //  comes back zero, that just means the table is empty.
0542     //
0543     //  Note that the -1 in the current hash tells it to start
0544     //  from the beginning.
0545     //
0546     findNext();
0547 }
0548 
0549 template <class TVal, class THasher>
0550 RefHashTableOfEnumerator<TVal, THasher>::~RefHashTableOfEnumerator()
0551 {
0552     if (fAdopted)
0553         delete fToEnum;
0554 }
0555 
0556 
0557 template <class TVal, class THasher> RefHashTableOfEnumerator<TVal, THasher>::
0558 RefHashTableOfEnumerator(const RefHashTableOfEnumerator<TVal, THasher>& toCopy) :
0559     XMLEnumerator<TVal>(toCopy)
0560     , XMemory(toCopy)
0561     , fAdopted(toCopy.fAdopted)
0562     , fCurElem(toCopy.fCurElem)
0563     , fCurHash(toCopy.fCurHash)
0564     , fToEnum(toCopy.fToEnum)
0565     , fMemoryManager(toCopy.fMemoryManager)
0566 {
0567 }
0568 // ---------------------------------------------------------------------------
0569 //  RefHashTableOfEnumerator: Enum interface
0570 // ---------------------------------------------------------------------------
0571 template <class TVal, class THasher>
0572 bool RefHashTableOfEnumerator<TVal, THasher>::hasMoreElements() const
0573 {
0574     //
0575     //  If our current has is at the max and there are no more elements
0576     //  in the current bucket, then no more elements.
0577     //
0578     if (!fCurElem && (fCurHash == fToEnum->fHashModulus))
0579         return false;
0580     return true;
0581 }
0582 
0583 template <class TVal, class THasher>
0584 TVal& RefHashTableOfEnumerator<TVal, THasher>::nextElement()
0585 {
0586     // Make sure we have an element to return
0587     if (!hasMoreElements())
0588         ThrowXMLwithMemMgr(NoSuchElementException, XMLExcepts::Enum_NoMoreElements, fMemoryManager);
0589 
0590     //
0591     //  Save the current element, then move up to the next one for the
0592     //  next time around.
0593     //
0594     RefHashTableBucketElem<TVal>* saveElem = fCurElem;
0595     findNext();
0596 
0597     return *saveElem->fData;
0598 }
0599 
0600 template <class TVal, class THasher>
0601 void* RefHashTableOfEnumerator<TVal, THasher>::nextElementKey()
0602 {
0603     // Make sure we have an element to return
0604     if (!hasMoreElements())
0605         ThrowXMLwithMemMgr(NoSuchElementException, XMLExcepts::Enum_NoMoreElements, fMemoryManager);
0606 
0607     //
0608     //  Save the current element, then move up to the next one for the
0609     //  next time around.
0610     //
0611     RefHashTableBucketElem<TVal>* saveElem = fCurElem;
0612     findNext();
0613 
0614     return saveElem->fKey;
0615 }
0616 
0617 template <class TVal, class THasher>
0618 void RefHashTableOfEnumerator<TVal, THasher>::Reset()
0619 {
0620     fCurHash = (XMLSize_t)-1;
0621     fCurElem = 0;
0622     findNext();
0623 }
0624 
0625 
0626 
0627 // ---------------------------------------------------------------------------
0628 //  RefHashTableOfEnumerator: Private helper methods
0629 // ---------------------------------------------------------------------------
0630 template <class TVal, class THasher>
0631 void RefHashTableOfEnumerator<TVal, THasher>::findNext()
0632 {
0633     //
0634     //  If there is a current element, move to its next element. If this
0635     //  hits the end of the bucket, the next block will handle the rest.
0636     //
0637     if (fCurElem)
0638         fCurElem = fCurElem->fNext;
0639 
0640     //
0641     //  If the current element is null, then we have to move up to the
0642     //  next hash value. If that is the hash modulus, then we cannot
0643     //  go further.
0644     //
0645     if (!fCurElem)
0646     {
0647         fCurHash++;
0648         if (fCurHash == fToEnum->fHashModulus)
0649             return;
0650 
0651         // Else find the next non-empty bucket
0652         while (fToEnum->fBucketList[fCurHash]==0)
0653         {
0654             // Bump to the next hash value. If we max out return
0655             fCurHash++;
0656             if (fCurHash == fToEnum->fHashModulus)
0657                 return;
0658         }
0659         fCurElem = fToEnum->fBucketList[fCurHash];
0660     }
0661 }
0662 
0663 XERCES_CPP_NAMESPACE_END