source: NonGTP/Xerces/xerces/include/xercesc/util/RefHashTableOf.c @ 358

Revision 358, 22.5 KB checked in by bittner, 19 years ago (diff)

xerces added

Line 
1/*
2 * Copyright 1999-2000,2004 The Apache Software Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/**
18 * $Log: RefHashTableOf.c,v $
19 * Revision 1.16  2004/09/08 13:56:23  peiyongz
20 * Apache License Version 2.0
21 *
22 * Revision 1.15  2004/04/22 10:47:44  cargilld
23 * Misc fix to update fCount in the correct place.
24 *
25 * Revision 1.14  2004/03/01 15:03:08  peiyongz
26 * new getter: getHashModulus
27 *
28 * Revision 1.13  2004/01/29 11:48:46  cargilld
29 * Code cleanup changes to get rid of various compiler diagnostic messages.
30 *
31 * Revision 1.12  2003/12/17 00:18:35  cargilld
32 * Update to memory management so that the static memory manager (one used to call Initialize) is only for static data.
33 *
34 * Revision 1.11  2003/08/20 11:51:39  gareth
35 * Reorderd initializer list to prevent compiler warning.
36 *
37 * Revision 1.10  2003/05/18 14:02:05  knoaman
38 * Memory manager implementation: pass per instance manager.
39 *
40 * Revision 1.9  2003/05/16 21:36:59  knoaman
41 * Memory manager implementation: Modify constructors to pass in the memory manager.
42 *
43 * Revision 1.8  2003/05/15 19:04:35  knoaman
44 * Partial implementation of the configurable memory manager.
45 *
46 * Revision 1.7  2003/05/15 10:37:08  gareth
47 * Optimization. We now resize the hash when appropriate. Patch by Nathan Codding.
48 *
49 * Revision 1.6  2002/11/04 15:22:04  tng
50 * C++ Namespace Support.
51 *
52 * Revision 1.5  2002/07/11 18:49:53  knoaman
53 * Add setAdoptElements method.
54 * Rename removeBucketElemSafe to orphanKey.
55 *
56 * Revision 1.4  2002/07/05 11:31:04  tng
57 * Fix typo.
58 *
59 * Revision 1.3  2002/07/04 15:24:57  tng
60 * DOM L3: add transferElement and removeBucketElemSafe for use in DOMDocument::renameNode.
61 *
62 * Revision 1.2  2002/06/12 17:14:03  tng
63 * Add function cleanup, reinitialize and nextElementKey for ease of use.
64 *
65 * Revision 1.1.1.1  2002/02/01 22:22:12  peiyongz
66 * sane_include
67 *
68 * Revision 1.9  2001/07/19 18:43:18  peiyongz
69 * fix: detect null poiniter in enumerator's ctor.
70 *
71 * Revision 1.8  2001/06/04 13:45:04  tng
72 * The "hash" argument clashes with STL hash.  Fixed by Pei Yong Zhang.
73 *
74 * Revision 1.7  2000/09/06 00:24:16  andyh
75 * Clean up misc compiler warnings
76 *
77 * Revision 1.6  2000/07/07 22:16:50  jpolast
78 * remove old put(value) function.  use put(key,value) instead.
79 *
80 * Revision 1.5  2000/06/29 18:27:09  jpolast
81 * bug fix for passing hasher class references to constructor
82 *
83 * Revision 1.4  2000/06/27 22:11:12  jpolast
84 * added more general functionality to hashtables.
85 * able to specify which hasher to use.
86 * default: HashXMLCh [hashes XMLCh* strings]
87 *
88 * future todo: make hasher class references static so only
89 * one instance of a hasher is ever created.
90 *
91 * Revision 1.3  2000/03/02 19:54:44  roddey
92 * This checkin includes many changes done while waiting for the
93 * 1.1.0 code to be finished. I can't list them all here, but a list is
94 * available elsewhere.
95 *
96 * Revision 1.2  2000/02/06 07:48:03  rahulj
97 * Year 2K copyright swat.
98 *
99 * Revision 1.1.1.1  1999/11/09 01:04:59  twl
100 * Initial checkin
101 *
102 * Revision 1.2  1999/11/08 20:45:12  rahul
103 * Swat for adding in Product name and CVS comment log variable.
104 *
105 */
106
107
108// ---------------------------------------------------------------------------
109//  Include
110// ---------------------------------------------------------------------------
111#if defined(XERCES_TMPLSINC)
112#include <xercesc/util/RefHashTableOf.hpp>
113#endif
114
115#include <xercesc/util/NullPointerException.hpp>
116
117XERCES_CPP_NAMESPACE_BEGIN
118
119// ---------------------------------------------------------------------------
120//  RefHashTableOf: Constructors and Destructor
121// ---------------------------------------------------------------------------
122template <class TVal>
123RefHashTableOf<TVal>::RefHashTableOf( const unsigned int modulus
124                                    , const bool adoptElems
125                                    , MemoryManager* const manager)
126
127    : fMemoryManager(manager)
128    , fAdoptedElems(adoptElems)
129    , fBucketList(0)
130    , fHashModulus(modulus)
131    , fInitialModulus(modulus)
132    , fCount(0)
133    , fHash(0)
134
135{
136    initialize(modulus);
137       
138        // create default hasher
139        fHash = new (fMemoryManager) HashXMLCh();
140}
141
142template <class TVal>
143RefHashTableOf<TVal>::RefHashTableOf( const unsigned int modulus
144                                    , const bool adoptElems
145                                    , HashBase* hashBase
146                                    , MemoryManager* const manager)
147
148    : fMemoryManager(manager)
149    , fAdoptedElems(adoptElems)
150    , fBucketList(0)
151    , fHashModulus(modulus)
152    , fInitialModulus(modulus)
153    , fCount(0)
154    , fHash(0)
155{
156    initialize(modulus);
157    // set hasher
158    fHash = hashBase;
159}
160
161template <class TVal>
162RefHashTableOf<TVal>::RefHashTableOf(const unsigned int modulus
163                                     , MemoryManager* const manager)
164
165    : fMemoryManager(manager)
166    , fAdoptedElems(true)
167    , fBucketList(0)
168    , fHashModulus(modulus)
169    , fInitialModulus(modulus)
170    , fCount(0)
171    , fHash(0)
172{
173    initialize(modulus);
174
175    // create default hasher
176    fHash = new (fMemoryManager) HashXMLCh();
177}
178
179template <class TVal> void RefHashTableOf<TVal>::initialize(const unsigned int modulus)
180{
181    if (modulus == 0)
182        ThrowXMLwithMemMgr(IllegalArgumentException, XMLExcepts::HshTbl_ZeroModulus, fMemoryManager);
183
184    // Allocate the bucket list and zero them
185    fBucketList = (RefHashTableBucketElem<TVal>**) fMemoryManager->allocate
186    (
187        fHashModulus * sizeof(RefHashTableBucketElem<TVal>*)
188    ); //new RefHashTableBucketElem<TVal>*[fHashModulus];
189    for (unsigned int index = 0; index < fHashModulus; index++)
190        fBucketList[index] = 0;
191}
192
193template <class TVal> RefHashTableOf<TVal>::~RefHashTableOf()
194{
195    removeAll();
196
197    // Then delete the bucket list & hasher
198    fMemoryManager->deallocate(fBucketList); //delete [] fBucketList;
199    delete fHash;
200}
201
202
203// ---------------------------------------------------------------------------
204//  RefHashTableOf: Element management
205// ---------------------------------------------------------------------------
206template <class TVal> bool RefHashTableOf<TVal>::isEmpty() const
207{
208    // Just check the bucket list for non-empty elements
209    for (unsigned int buckInd = 0; buckInd < fHashModulus; buckInd++)
210    {
211        if (fBucketList[buckInd] != 0)
212            return false;
213    }
214    return true;
215}
216
217template <class TVal> bool RefHashTableOf<TVal>::
218containsKey(const void* const key) const
219{
220    unsigned int hashVal;
221    const RefHashTableBucketElem<TVal>* findIt = findBucketElem(key, hashVal);
222    return (findIt != 0);
223}
224
225template <class TVal> void RefHashTableOf<TVal>::
226removeKey(const void* const key)
227{
228    unsigned int hashVal;
229    removeBucketElem(key, hashVal);
230}
231
232template <class TVal> void RefHashTableOf<TVal>::removeAll()
233{
234    // Clean up the buckets first
235    for (unsigned int buckInd = 0; buckInd < fHashModulus; buckInd++)
236    {
237        // Get the bucket list head for this entry
238        RefHashTableBucketElem<TVal>* curElem = fBucketList[buckInd];
239        RefHashTableBucketElem<TVal>* nextElem;
240        while (curElem)
241        {
242            // Save the next element before we hose this one
243            nextElem = curElem->fNext;
244
245            // If we adopted the data, then delete it too
246            //    (Note:  the userdata hash table instance has data type of void *.
247            //    This will generate compiler warnings here on some platforms, but they
248            //    can be ignored since fAdoptedElements is false.
249            if (fAdoptedElems)
250                delete curElem->fData;
251
252            // Then delete the current element and move forward
253            delete curElem;
254            curElem = nextElem;
255        }
256
257        // Clean out this entry
258        fBucketList[buckInd] = 0;
259    }
260
261    fCount = 0;
262}
263
264// This method returns the data associated with a key. The key entry is deleted. The caller
265// now owns the returned data (case of hashtable adopting the data).
266// This function is called by transferElement so that the undeleted data can be transferred
267// to a new key which will own that data.
268template <class TVal> TVal* RefHashTableOf<TVal>::
269orphanKey(const void* const key)
270{
271    // Hash the key
272    TVal* retVal = 0;
273    unsigned int hashVal = fHash->getHashVal(key, fHashModulus, fMemoryManager);
274    if (hashVal > fHashModulus)
275        ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::HshTbl_BadHashFromKey, fMemoryManager);
276
277    //
278    //  Search the given bucket for this key. Keep up with the previous
279    //  element so we can patch around it.
280    //
281    RefHashTableBucketElem<TVal>* curElem = fBucketList[hashVal];
282    RefHashTableBucketElem<TVal>* lastElem = 0;
283
284    while (curElem)
285    {
286        if (fHash->equals(key, curElem->fKey))
287        {
288            if (!lastElem)
289            {
290                // It was the first in the bucket
291                fBucketList[hashVal] = curElem->fNext;
292            }
293             else
294            {
295                // Patch around the current element
296                lastElem->fNext = curElem->fNext;
297            }
298
299            retVal = curElem->fData;
300
301            // Delete the current element
302            delete curElem;
303            break;
304        }
305
306        // Move both pointers upwards
307        lastElem = curElem;
308        curElem = curElem->fNext;
309    }
310
311    // We never found that key
312    if (!retVal)
313        ThrowXMLwithMemMgr(NoSuchElementException, XMLExcepts::HshTbl_NoSuchKeyExists, fMemoryManager);
314
315    return retVal;
316}
317
318//
319// cleanup():
320//   similar to destructor
321//   called to cleanup the memory, in case destructor cannot be called
322//
323template <class TElem> void RefHashTableOf<TElem>::cleanup()
324{
325    removeAll();
326
327    // Then delete the bucket list & hasher
328    fMemoryManager->deallocate(fBucketList); //delete [] fBucketList;
329    fBucketList = 0;
330    delete fHash;
331}
332
333//
334// reinitialize():
335//   similar to constructor
336//   called to re-construct the fElemList from scratch again
337//
338template <class TElem> void RefHashTableOf<TElem>::reinitialize(HashBase* hashBase)
339{
340    if (fBucketList || fHash)
341        cleanup();
342
343    fHashModulus = fInitialModulus;
344    initialize(fHashModulus);
345
346    if (hashBase)
347        fHash = hashBase;
348    else
349        fHash = new (fMemoryManager) HashXMLCh();   // create default hasher
350}
351
352
353
354// this function transfer the data from key1 to key2
355// this is equivalent to calling
356//  1.  get(key1) to retrieve the data,
357//  2.  removeKey(key1),
358//  3.  and then put(key2, data)
359// except that the data is not deleted in "removeKey" even it is adopted so that it
360// can be transferred to key2.
361// whatever key2 has originally will be purged (if adopted)
362template <class TElem> void RefHashTableOf<TElem>::transferElement(const void* const key1, void* key2)
363{
364    put(key2, orphanKey(key1));
365}
366
367
368// ---------------------------------------------------------------------------
369//  RefHashTableOf: Getters
370// ---------------------------------------------------------------------------
371template <class TVal> TVal* RefHashTableOf<TVal>::get(const void* const key)
372{
373    unsigned int hashVal;
374    RefHashTableBucketElem<TVal>* findIt = findBucketElem(key, hashVal);
375    if (!findIt)
376        return 0;
377    return findIt->fData;
378}
379
380template <class TVal> const TVal* RefHashTableOf<TVal>::
381get(const void* const key) const
382{
383    unsigned int hashVal;
384    const RefHashTableBucketElem<TVal>* findIt = findBucketElem(key, hashVal);
385    if (!findIt)
386        return 0;
387    return findIt->fData;
388}
389
390template <class TVal>
391MemoryManager* RefHashTableOf<TVal>::getMemoryManager() const
392{
393    return fMemoryManager;
394}
395
396template <class TVal>
397unsigned int RefHashTableOf<TVal>::getHashModulus() const
398{
399    return fHashModulus;
400}
401
402// ---------------------------------------------------------------------------
403//  RefHashTableOf: Getters
404// ---------------------------------------------------------------------------
405template <class TVal>
406void RefHashTableOf<TVal>::setAdoptElements(const bool aValue)
407{
408    fAdoptedElems = aValue;
409}
410
411// ---------------------------------------------------------------------------
412//  RefHashTableOf: Putters
413// ---------------------------------------------------------------------------
414template <class TVal> void RefHashTableOf<TVal>::put(void* key, TVal* const valueToAdopt)
415{
416    // Apply 0.75 load factor to find threshold.
417    unsigned int threshold = fHashModulus * 3 / 4;
418   
419    // If we've grown too big, expand the table and rehash.
420    if (fCount >= threshold)
421        rehash();
422
423    // First see if the key exists already
424    unsigned int hashVal;
425    RefHashTableBucketElem<TVal>* newBucket = findBucketElem(key, hashVal);
426
427    //
428    //  If so,then update its value. If not, then we need to add it to
429    //  the right bucket
430    //
431    if (newBucket)
432    {
433        if (fAdoptedElems)
434            delete newBucket->fData;
435        newBucket->fData = valueToAdopt;
436                newBucket->fKey = key;
437    }
438     else
439    {
440        newBucket = new (fMemoryManager) RefHashTableBucketElem<TVal>(key, valueToAdopt, fBucketList[hashVal]);
441        fBucketList[hashVal] = newBucket;
442        fCount++;
443    }
444}
445
446
447
448// ---------------------------------------------------------------------------
449//  RefHashTableOf: Private methods
450// ---------------------------------------------------------------------------
451template <class TVal> void RefHashTableOf<TVal>::rehash()
452{
453    unsigned int index;
454    unsigned int oldMod = fHashModulus;
455    fHashModulus *= 2;
456   
457    RefHashTableBucketElem<TVal>** oldBucketList = fBucketList;
458   
459    fBucketList = (RefHashTableBucketElem<TVal>**) fMemoryManager->allocate
460    (
461        fHashModulus * sizeof(RefHashTableBucketElem<TVal>*)
462    );//new RefHashTableBucketElem<TVal>*[fHashModulus];
463    for (index = 0; index < fHashModulus; index++)
464        fBucketList[index] = 0;
465   
466   
467    // Rehash all existing entries.
468    for (index = 0; index < oldMod; index++)
469    {
470        // Get the bucket list head for this entry
471        RefHashTableBucketElem<TVal>* curElem = oldBucketList[index];
472        RefHashTableBucketElem<TVal>* nextElem;
473        while (curElem)
474        {
475            // Save the next element before we detach this one
476            nextElem = curElem->fNext;
477
478            unsigned int hashVal = fHash->getHashVal(curElem->fKey, fHashModulus, fMemoryManager);
479            if (hashVal > fHashModulus)
480                ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::HshTbl_BadHashFromKey, fMemoryManager);
481           
482            RefHashTableBucketElem<TVal>* newHeadElem = fBucketList[hashVal];
483           
484            // Insert at the start of this bucket's list.
485            curElem->fNext = newHeadElem;
486            fBucketList[hashVal] = curElem;
487           
488            curElem = nextElem;
489        }
490    }
491           
492    fMemoryManager->deallocate(oldBucketList);//delete[] oldBucketList;
493   
494}
495
496template <class TVal> RefHashTableBucketElem<TVal>* RefHashTableOf<TVal>::
497findBucketElem(const void* const key, unsigned int& hashVal)
498{
499    // Hash the key
500    hashVal = fHash->getHashVal(key, fHashModulus, fMemoryManager);
501    if (hashVal > fHashModulus)
502        ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::HshTbl_BadHashFromKey, fMemoryManager);
503
504    // Search that bucket for the key
505    RefHashTableBucketElem<TVal>* curElem = fBucketList[hashVal];
506    while (curElem)
507    {
508                if (fHash->equals(key, curElem->fKey))
509            return curElem;
510
511        curElem = curElem->fNext;
512    }
513    return 0;
514}
515
516template <class TVal> const RefHashTableBucketElem<TVal>* RefHashTableOf<TVal>::
517findBucketElem(const void* const key, unsigned int& hashVal) const
518{
519    // Hash the key
520    hashVal = fHash->getHashVal(key, fHashModulus, fMemoryManager);
521    if (hashVal > fHashModulus)
522        ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::HshTbl_BadHashFromKey, fMemoryManager);
523
524    // Search that bucket for the key
525    const RefHashTableBucketElem<TVal>* curElem = fBucketList[hashVal];
526    while (curElem)
527    {
528        if (fHash->equals(key, curElem->fKey))
529            return curElem;
530
531        curElem = curElem->fNext;
532    }
533    return 0;
534}
535
536
537template <class TVal> void RefHashTableOf<TVal>::
538removeBucketElem(const void* const key, unsigned int& hashVal)
539{
540    // Hash the key
541    hashVal = fHash->getHashVal(key, fHashModulus, fMemoryManager);
542    if (hashVal > fHashModulus)
543        ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::HshTbl_BadHashFromKey, fMemoryManager);
544
545    //
546    //  Search the given bucket for this key. Keep up with the previous
547    //  element so we can patch around it.
548    //
549    RefHashTableBucketElem<TVal>* curElem = fBucketList[hashVal];
550    RefHashTableBucketElem<TVal>* lastElem = 0;
551
552    while (curElem)
553    {
554        if (fHash->equals(key, curElem->fKey))
555        {
556            if (!lastElem)
557            {
558                // It was the first in the bucket
559                fBucketList[hashVal] = curElem->fNext;
560            }
561             else
562            {
563                // Patch around the current element
564                lastElem->fNext = curElem->fNext;
565            }
566
567            // If we adopted the elements, then delete the data
568            if (fAdoptedElems)
569                delete curElem->fData;
570
571            // Delete the current element
572            delete curElem;
573
574            fCount--;
575
576            return;
577        }
578
579        // Move both pointers upwards
580        lastElem = curElem;
581        curElem = curElem->fNext;
582    }
583
584    // We never found that key
585    ThrowXMLwithMemMgr(NoSuchElementException, XMLExcepts::HshTbl_NoSuchKeyExists, fMemoryManager);
586}
587
588
589
590// ---------------------------------------------------------------------------
591//  RefHashTableOfEnumerator: Constructors and Destructor
592// ---------------------------------------------------------------------------
593template <class TVal> RefHashTableOfEnumerator<TVal>::
594RefHashTableOfEnumerator(RefHashTableOf<TVal>* const toEnum
595                         , const bool adopt
596                         , MemoryManager* const manager)
597        : fAdopted(adopt), fCurElem(0), fCurHash((unsigned int)-1), fToEnum(toEnum)
598    , fMemoryManager(manager)
599{
600    if (!toEnum)
601        ThrowXMLwithMemMgr(NullPointerException, XMLExcepts::CPtr_PointerIsZero, fMemoryManager);
602
603    //
604    //  Find the next available bucket element in the hash table. If it
605    //  comes back zero, that just means the table is empty.
606    //
607    //  Note that the -1 in the current hash tells it to start from the
608    //  beginning.
609    //
610    findNext();
611}
612
613template <class TVal> RefHashTableOfEnumerator<TVal>::~RefHashTableOfEnumerator()
614{
615    if (fAdopted)
616        delete fToEnum;
617}
618
619
620template <class TVal> RefHashTableOfEnumerator<TVal>::
621RefHashTableOfEnumerator(const RefHashTableOfEnumerator<TVal>& toCopy) :
622    fAdopted(toCopy.fAdopted)
623    , fCurElem(toCopy.fCurElem)
624    , fCurHash(toCopy.fCurHash)
625    , fToEnum(toCopy.fToEnum)
626    , fMemoryManager(toCopy.fMemoryManager)
627{
628}
629// ---------------------------------------------------------------------------
630//  RefHashTableOfEnumerator: Enum interface
631// ---------------------------------------------------------------------------
632template <class TVal> bool RefHashTableOfEnumerator<TVal>::hasMoreElements() const
633{
634    //
635    //  If our current has is at the max and there are no more elements
636    //  in the current bucket, then no more elements.
637    //
638    if (!fCurElem && (fCurHash == fToEnum->fHashModulus))
639        return false;
640    return true;
641}
642
643template <class TVal> TVal& RefHashTableOfEnumerator<TVal>::nextElement()
644{
645    // Make sure we have an element to return
646    if (!hasMoreElements())
647        ThrowXMLwithMemMgr(NoSuchElementException, XMLExcepts::Enum_NoMoreElements, fMemoryManager);
648
649    //
650    //  Save the current element, then move up to the next one for the
651    //  next time around.
652    //
653    RefHashTableBucketElem<TVal>* saveElem = fCurElem;
654    findNext();
655
656    return *saveElem->fData;
657}
658
659template <class TVal> void* RefHashTableOfEnumerator<TVal>::nextElementKey()
660{
661    // Make sure we have an element to return
662    if (!hasMoreElements())
663        ThrowXMLwithMemMgr(NoSuchElementException, XMLExcepts::Enum_NoMoreElements, fMemoryManager);
664
665    //
666    //  Save the current element, then move up to the next one for the
667    //  next time around.
668    //
669    RefHashTableBucketElem<TVal>* saveElem = fCurElem;
670    findNext();
671
672    return saveElem->fKey;
673}
674
675template <class TVal> void RefHashTableOfEnumerator<TVal>::Reset()
676{
677    fCurHash = (unsigned int)-1;
678    fCurElem = 0;
679    findNext();
680}
681
682
683
684// ---------------------------------------------------------------------------
685//  RefHashTableOfEnumerator: Private helper methods
686// ---------------------------------------------------------------------------
687template <class TVal> void RefHashTableOfEnumerator<TVal>::findNext()
688{
689    //
690    //  If there is a current element, move to its next element. If this
691    //  hits the end of the bucket, the next block will handle the rest.
692    //
693    if (fCurElem)
694        fCurElem = fCurElem->fNext;
695
696    //
697    //  If the current element is null, then we have to move up to the
698    //  next hash value. If that is the hash modulus, then we cannot
699    //  go further.
700    //
701    if (!fCurElem)
702    {
703        fCurHash++;
704        if (fCurHash == fToEnum->fHashModulus)
705            return;
706
707        // Else find the next non-empty bucket
708        while (true)
709        {
710            if (fToEnum->fBucketList[fCurHash])
711                break;
712
713            // Bump to the next hash value. If we max out return
714            fCurHash++;
715            if (fCurHash == fToEnum->fHashModulus)
716                return;
717        }
718        fCurElem = fToEnum->fBucketList[fCurHash];
719    }
720}
721
722XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.