source: NonGTP/Xerces/xerces-c_2_8_0/include/xercesc/util/RefHash2KeysTableOf.c @ 2674

Revision 2674, 20.8 KB checked in by mattausch, 16 years ago (diff)
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/*
19 * $Id: RefHash2KeysTableOf.c 568078 2007-08-21 11:43:25Z amassari $
20 */
21
22
23// ---------------------------------------------------------------------------
24//  Include
25// ---------------------------------------------------------------------------
26#if defined(XERCES_TMPLSINC)
27#include <xercesc/util/RefHash2KeysTableOf.hpp>
28#endif
29
30#include <xercesc/util/Janitor.hpp>
31#include <xercesc/util/NullPointerException.hpp>
32#include <assert.h>
33#include <new>
34
35XERCES_CPP_NAMESPACE_BEGIN
36
37// ---------------------------------------------------------------------------
38//  RefHash2KeysTableOf: Constructors and Destructor
39// ---------------------------------------------------------------------------
40template <class TVal>
41RefHash2KeysTableOf<TVal>::RefHash2KeysTableOf( const unsigned int   modulus
42                                              , const bool           adoptElems
43                                              , MemoryManager* const manager)
44    : fMemoryManager(manager)
45        , fAdoptedElems(adoptElems)
46    , fBucketList(0)
47    , fHashModulus(modulus)
48    , fCount(0)
49    , fHash(0)
50{
51    initialize(modulus);
52       
53        // create default hasher
54        fHash = new (fMemoryManager) HashXMLCh();
55}
56
57template <class TVal>
58RefHash2KeysTableOf<TVal>::RefHash2KeysTableOf( const unsigned int   modulus
59                                              , const bool           adoptElems
60                                              , HashBase*            hashBase
61                                              , MemoryManager* const manager)
62        : fMemoryManager(manager)
63    , fAdoptedElems(adoptElems)
64    , fBucketList(0)
65    , fHashModulus(modulus)
66    , fCount(0)
67    , fHash(0)
68{
69        initialize(modulus);
70        // set hasher
71        fHash = hashBase;
72}
73
74template <class TVal>
75RefHash2KeysTableOf<TVal>::RefHash2KeysTableOf(const unsigned int modulus,
76                                               MemoryManager* const manager)
77        : fMemoryManager(manager)
78    , fAdoptedElems(true)
79    , fBucketList(0)
80    , fHashModulus(modulus)
81    , fCount(0)
82    , fHash(0)
83{
84        initialize(modulus);
85
86        // create default hasher
87        fHash = new (fMemoryManager) HashXMLCh();
88}
89
90template <class TVal>
91void RefHash2KeysTableOf<TVal>::initialize(const unsigned int modulus)
92{
93        if (modulus == 0)
94        ThrowXMLwithMemMgr(IllegalArgumentException, XMLExcepts::HshTbl_ZeroModulus, fMemoryManager);
95
96    // Allocate the bucket list and zero them
97    fBucketList = (RefHash2KeysTableBucketElem<TVal>**) fMemoryManager->allocate
98    (
99        fHashModulus * sizeof(RefHash2KeysTableBucketElem<TVal>*)
100    ); //new RefHash2KeysTableBucketElem<TVal>*[fHashModulus];
101    memset(fBucketList, 0, sizeof(fBucketList[0]) * fHashModulus);
102}
103
104template <class TVal> RefHash2KeysTableOf<TVal>::~RefHash2KeysTableOf()
105{
106    removeAll();
107
108    // Then delete the bucket list & hasher
109    fMemoryManager->deallocate(fBucketList); //delete [] fBucketList;
110        delete fHash;
111}
112
113
114// ---------------------------------------------------------------------------
115//  RefHash2KeysTableOf: Element management
116// ---------------------------------------------------------------------------
117template <class TVal> bool RefHash2KeysTableOf<TVal>::isEmpty() const
118{
119    return (fCount==0);
120}
121
122template <class TVal> bool RefHash2KeysTableOf<TVal>::
123containsKey(const void* const key1, const int key2) const
124{
125    unsigned int hashVal;
126    const RefHash2KeysTableBucketElem<TVal>* findIt = findBucketElem(key1, key2, hashVal);
127    return (findIt != 0);
128}
129
130template <class TVal> void RefHash2KeysTableOf<TVal>::
131removeKey(const void* const key1, const int key2)
132{
133    // Hash the key
134    unsigned int hashVal = fHash->getHashVal(key1, fHashModulus);
135    assert(hashVal < fHashModulus);
136
137    //
138    //  Search the given bucket for this key. Keep up with the previous
139    //  element so we can patch around it.
140    //
141    RefHash2KeysTableBucketElem<TVal>* curElem = fBucketList[hashVal];
142    RefHash2KeysTableBucketElem<TVal>* lastElem = 0;
143
144    while (curElem)
145    {
146        if (fHash->equals(key1, curElem->fKey1) && (key2==curElem->fKey2))
147        {
148            if (!lastElem)
149            {
150                // It was the first in the bucket
151                fBucketList[hashVal] = curElem->fNext;
152            }
153            else
154            {
155                // Patch around the current element
156                lastElem->fNext = curElem->fNext;
157            }
158
159            // If we adopted the elements, then delete the data
160            if (fAdoptedElems)
161                delete curElem->fData;
162
163            // Delete the current element
164            // delete curElem;
165            // destructor is empty...
166            // curElem->~RefHash2KeysTableBucketElem();
167            fMemoryManager->deallocate(curElem);           
168            fCount--;
169            return;
170        }
171
172        // Move both pointers upwards
173        lastElem = curElem;
174        curElem = curElem->fNext;
175    }
176
177    // We never found that key
178    ThrowXMLwithMemMgr(NoSuchElementException, XMLExcepts::HshTbl_NoSuchKeyExists, fMemoryManager);
179}
180
181template <class TVal> void RefHash2KeysTableOf<TVal>::
182removeKey(const void* const key1)
183{
184    // Hash the key
185    unsigned int hashVal = fHash->getHashVal(key1, fHashModulus);
186    assert(hashVal < fHashModulus);
187
188    //
189    //  Search the given bucket for this key. Keep up with the previous
190    //  element so we can patch around it.
191    //
192    RefHash2KeysTableBucketElem<TVal>* curElem = fBucketList[hashVal];
193    RefHash2KeysTableBucketElem<TVal>* lastElem = 0;
194
195    while (curElem)
196    {
197        if (fHash->equals(key1, curElem->fKey1))
198        {
199            if (!lastElem)
200            {
201                // It was the first in the bucket
202                fBucketList[hashVal] = curElem->fNext;
203            }
204            else
205            {
206                // Patch around the current element
207                lastElem->fNext = curElem->fNext;
208            }
209
210            // If we adopted the elements, then delete the data
211            if (fAdoptedElems)
212                delete curElem->fData;
213
214            RefHash2KeysTableBucketElem<TVal>* toBeDeleted=curElem;
215            curElem = curElem->fNext;
216
217            // Delete the current element
218            // delete curElem;
219            // destructor is empty...
220            // curElem->~RefHash2KeysTableBucketElem();
221            fMemoryManager->deallocate(toBeDeleted);
222            fCount--;
223        }
224        else
225        {
226            // Move both pointers upwards
227            lastElem = curElem;
228            curElem = curElem->fNext;
229        }
230    }
231}
232
233template <class TVal> void RefHash2KeysTableOf<TVal>::removeAll()
234{
235    if(isEmpty())
236        return;
237
238    // Clean up the buckets first
239    for (unsigned int buckInd = 0; buckInd < fHashModulus; buckInd++)
240    {
241        // Get the bucket list head for this entry
242        RefHash2KeysTableBucketElem<TVal>* curElem = fBucketList[buckInd];
243        RefHash2KeysTableBucketElem<TVal>* nextElem;
244        while (curElem)
245        {
246            // Save the next element before we hose this one
247            nextElem = curElem->fNext;
248
249            // If we adopted the data, then delete it too
250            //    (Note:  the userdata hash table instance has data type of void *.
251            //    This will generate compiler warnings here on some platforms, but they
252            //    can be ignored since fAdoptedElements is false.
253            if (fAdoptedElems)
254                delete curElem->fData;
255
256            // Then delete the current element and move forward
257            // destructor is empty...
258            // curElem->~RefHash2KeysTableBucketElem();
259            fMemoryManager->deallocate(curElem);
260            curElem = nextElem;
261        }
262
263        // Clean out this entry
264        fBucketList[buckInd] = 0;
265    }
266    fCount=0;
267}
268
269// this function transfer the data from key1 to key2
270template <class TVal> void RefHash2KeysTableOf<TVal>::transferElement(const void* const key1, void* key2)
271{
272    // Hash the key
273    unsigned int hashVal = fHash->getHashVal(key1, fHashModulus);
274    assert(hashVal < fHashModulus);
275
276    //
277    //  Search the given bucket for this key. Keep up with the previous
278    //  element so we can patch around it.
279    //
280    RefHash2KeysTableBucketElem<TVal>* curElem = fBucketList[hashVal];
281    RefHash2KeysTableBucketElem<TVal>* lastElem = 0;
282
283    while (curElem)
284    {
285        // if this element has the same primary key, remove it and add it using the new primary key
286        if (fHash->equals(key1, curElem->fKey1))
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            // this code comes from put(), but it doesn't update fCount
300            unsigned int hashVal2;
301            RefHash2KeysTableBucketElem<TVal>* newBucket = findBucketElem(key2, curElem->fKey2, hashVal2);
302            if (newBucket)
303            {
304                if (fAdoptedElems)
305                    delete newBucket->fData;
306                newBucket->fData = curElem->fData;
307                        newBucket->fKey1 = key2;
308                        newBucket->fKey2 = curElem->fKey2;
309            }
310             else
311            {
312                newBucket =
313                    new (fMemoryManager->allocate(sizeof(RefHash2KeysTableBucketElem<TVal>)))
314                    RefHash2KeysTableBucketElem<TVal>(key2, curElem->fKey2, curElem->fData, fBucketList[hashVal2]);
315                fBucketList[hashVal2] = newBucket;
316            }
317
318            RefHash2KeysTableBucketElem<TVal>* elemToDelete = curElem;
319           
320            // Update just curElem; lastElem must stay the same
321            curElem = curElem->fNext;
322
323            // Delete the current element
324            // delete elemToDelete;
325            // destructor is empty...
326            // curElem->~RefHash2KeysTableBucketElem();
327            fMemoryManager->deallocate(elemToDelete);
328        }
329        else
330        {
331            // Move both pointers upwards
332            lastElem = curElem;
333            curElem = curElem->fNext;
334        }
335    }
336}
337
338
339
340// ---------------------------------------------------------------------------
341//  RefHash2KeysTableOf: Getters
342// ---------------------------------------------------------------------------
343template <class TVal> TVal* RefHash2KeysTableOf<TVal>::get(const void* const key1, const int key2)
344{
345    unsigned int hashVal;
346    RefHash2KeysTableBucketElem<TVal>* findIt = findBucketElem(key1, key2, hashVal);
347    if (!findIt)
348        return 0;
349    return findIt->fData;
350}
351
352template <class TVal> const TVal* RefHash2KeysTableOf<TVal>::
353get(const void* const key1, const int key2) const
354{
355    unsigned int hashVal;
356    const RefHash2KeysTableBucketElem<TVal>* findIt = findBucketElem(key1, key2, hashVal);
357    if (!findIt)
358        return 0;
359    return findIt->fData;
360}
361
362template <class TVal>
363MemoryManager* RefHash2KeysTableOf<TVal>::getMemoryManager() const
364{
365    return fMemoryManager;
366}
367
368template <class TVal>
369unsigned int RefHash2KeysTableOf<TVal>::getHashModulus() const
370{
371    return fHashModulus;
372}
373
374// ---------------------------------------------------------------------------
375//  RefHash2KeysTableOf: Putters
376// ---------------------------------------------------------------------------
377template <class TVal> void RefHash2KeysTableOf<TVal>::put(void* key1, int key2, TVal* const valueToAdopt)
378{
379    // Apply 4 load factor to find threshold.
380    unsigned int threshold = fHashModulus * 4;
381   
382    // If we've grown too big, expand the table and rehash.
383    if (fCount >= threshold)
384        rehash();
385
386    // First see if the key exists already
387    unsigned int hashVal;
388    RefHash2KeysTableBucketElem<TVal>* newBucket = findBucketElem(key1, key2, hashVal);
389
390    //
391    //  If so,then update its value. If not, then we need to add it to
392    //  the right bucket
393    //
394    if (newBucket)
395    {
396        if (fAdoptedElems)
397            delete newBucket->fData;
398        newBucket->fData = valueToAdopt;
399                newBucket->fKey1 = key1;
400                newBucket->fKey2 = key2;
401    }
402     else
403    {
404        newBucket =
405            new (fMemoryManager->allocate(sizeof(RefHash2KeysTableBucketElem<TVal>)))
406            RefHash2KeysTableBucketElem<TVal>(key1, key2, valueToAdopt, fBucketList[hashVal]);
407        fBucketList[hashVal] = newBucket;
408        fCount++;
409    }
410}
411
412
413
414// ---------------------------------------------------------------------------
415//  RefHash2KeysTableOf: Private methods
416// ---------------------------------------------------------------------------
417template <class TVal> RefHash2KeysTableBucketElem<TVal>* RefHash2KeysTableOf<TVal>::
418findBucketElem(const void* const key1, const int key2, unsigned int& hashVal)
419{
420    // Hash the key
421    hashVal = fHash->getHashVal(key1, fHashModulus, fMemoryManager);
422    assert(hashVal < fHashModulus);
423
424    // Search that bucket for the key
425    RefHash2KeysTableBucketElem<TVal>* curElem = fBucketList[hashVal];
426    while (curElem)
427    {
428                if (key2==curElem->fKey2 && fHash->equals(key1, curElem->fKey1))
429            return curElem;
430
431        curElem = curElem->fNext;
432    }
433    return 0;
434}
435
436template <class TVal> const RefHash2KeysTableBucketElem<TVal>* RefHash2KeysTableOf<TVal>::
437findBucketElem(const void* const key1, const int key2, unsigned int& hashVal) const
438{
439    // Hash the key
440    hashVal = fHash->getHashVal(key1, fHashModulus, fMemoryManager);
441    assert(hashVal < fHashModulus);
442
443    // Search that bucket for the key
444    const RefHash2KeysTableBucketElem<TVal>* curElem = fBucketList[hashVal];
445    while (curElem)
446    {
447        if (fHash->equals(key1, curElem->fKey1) && (key2==curElem->fKey2))
448            return curElem;
449
450        curElem = curElem->fNext;
451    }
452    return 0;
453}
454
455
456template <class TVal> void RefHash2KeysTableOf<TVal>::
457rehash()
458{
459    const unsigned int newMod = (fHashModulus * 8)+1;
460
461    RefHash2KeysTableBucketElem<TVal>** newBucketList =
462        (RefHash2KeysTableBucketElem<TVal>**) fMemoryManager->allocate
463    (
464        newMod * sizeof(RefHash2KeysTableBucketElem<TVal>*)
465    );//new RefHash2KeysTableBucketElem<TVal>*[fHashModulus];
466
467    // Make sure the new bucket list is destroyed if an
468    // exception is thrown.
469    ArrayJanitor<RefHash2KeysTableBucketElem<TVal>*>  guard(newBucketList, fMemoryManager);
470
471    memset(newBucketList, 0, newMod * sizeof(newBucketList[0]));
472
473    // Rehash all existing entries.
474    for (unsigned int index = 0; index < fHashModulus; index++)
475    {
476        // Get the bucket list head for this entry
477        RefHash2KeysTableBucketElem<TVal>* curElem = fBucketList[index];
478        while (curElem)
479        {
480            // Save the next element before we detach this one
481            RefHash2KeysTableBucketElem<TVal>* nextElem = curElem->fNext;
482
483            const unsigned int hashVal = fHash->getHashVal(curElem->fKey1, newMod, fMemoryManager);
484            assert(hashVal < newMod);
485           
486            RefHash2KeysTableBucketElem<TVal>* newHeadElem = newBucketList[hashVal];
487           
488            // Insert at the start of this bucket's list.
489            curElem->fNext = newHeadElem;
490            newBucketList[hashVal] = curElem;
491           
492            curElem = nextElem;
493        }
494    }
495           
496    RefHash2KeysTableBucketElem<TVal>** const oldBucketList = fBucketList;
497
498    // Everything is OK at this point, so update the
499    // member variables.
500    fBucketList = guard.release();
501    fHashModulus = newMod;
502
503    // Delete the old bucket list.
504    fMemoryManager->deallocate(oldBucketList);//delete[] oldBucketList;
505   
506}
507
508
509
510// ---------------------------------------------------------------------------
511//  RefHash2KeysTableOfEnumerator: Constructors and Destructor
512// ---------------------------------------------------------------------------
513template <class TVal> RefHash2KeysTableOfEnumerator<TVal>::
514RefHash2KeysTableOfEnumerator(RefHash2KeysTableOf<TVal>* const toEnum
515                              , const bool adopt
516                              , MemoryManager* const manager)
517        : fAdopted(adopt), fCurElem(0), fCurHash((unsigned int)-1), fToEnum(toEnum)
518    , fMemoryManager(manager)
519    , fLockPrimaryKey(0)
520{
521    if (!toEnum)
522        ThrowXMLwithMemMgr(NullPointerException, XMLExcepts::CPtr_PointerIsZero, fMemoryManager);
523
524    //
525    //  Find the next available bucket element in the hash table. If it
526    //  comes back zero, that just means the table is empty.
527    //
528    //  Note that the -1 in the current hash tells it to start from the
529    //  beginning.
530    //
531    findNext();
532}
533
534template <class TVal> RefHash2KeysTableOfEnumerator<TVal>::~RefHash2KeysTableOfEnumerator()
535{
536    if (fAdopted)
537        delete fToEnum;
538}
539
540
541// ---------------------------------------------------------------------------
542//  RefHash2KeysTableOfEnumerator: Enum interface
543// ---------------------------------------------------------------------------
544template <class TVal> bool RefHash2KeysTableOfEnumerator<TVal>::hasMoreElements() const
545{
546    //
547    //  If our current has is at the max and there are no more elements
548    //  in the current bucket, then no more elements.
549    //
550    if (!fCurElem && (fCurHash == fToEnum->fHashModulus))
551        return false;
552    return true;
553}
554
555template <class TVal> TVal& RefHash2KeysTableOfEnumerator<TVal>::nextElement()
556{
557    // Make sure we have an element to return
558    if (!hasMoreElements())
559        ThrowXMLwithMemMgr(NoSuchElementException, XMLExcepts::Enum_NoMoreElements, fMemoryManager);
560
561    //
562    //  Save the current element, then move up to the next one for the
563    //  next time around.
564    //
565    RefHash2KeysTableBucketElem<TVal>* saveElem = fCurElem;
566    findNext();
567
568    return *saveElem->fData;
569}
570
571template <class TVal> void RefHash2KeysTableOfEnumerator<TVal>::nextElementKey(void*& retKey1, int& retKey2)
572{
573    // Make sure we have an element to return
574    if (!hasMoreElements())
575        ThrowXMLwithMemMgr(NoSuchElementException, XMLExcepts::Enum_NoMoreElements, fMemoryManager);
576
577    //
578    //  Save the current element, then move up to the next one for the
579    //  next time around.
580    //
581    RefHash2KeysTableBucketElem<TVal>* saveElem = fCurElem;
582    findNext();
583
584    retKey1 = saveElem->fKey1;
585    retKey2 = saveElem->fKey2;
586
587    return;
588}
589
590template <class TVal> void RefHash2KeysTableOfEnumerator<TVal>::Reset()
591{
592    if(fLockPrimaryKey)
593        fCurHash=fToEnum->fHash->getHashVal(fLockPrimaryKey, fToEnum->fHashModulus, fMemoryManager);
594    else
595        fCurHash = (unsigned int)-1;
596    fCurElem = 0;
597    findNext();
598}
599
600
601template <class TVal> void RefHash2KeysTableOfEnumerator<TVal>::setPrimaryKey(const void* key)
602{
603    fLockPrimaryKey=key;
604    Reset();
605}
606
607// ---------------------------------------------------------------------------
608//  RefHash2KeysTableOfEnumerator: Private helper methods
609// ---------------------------------------------------------------------------
610template <class TVal> void RefHash2KeysTableOfEnumerator<TVal>::findNext()
611{
612    //  Code to execute if we have to return only values with the primary key
613    if(fLockPrimaryKey)
614    {
615        if(!fCurElem)
616            fCurElem = fToEnum->fBucketList[fCurHash];
617        else
618            fCurElem = fCurElem->fNext;
619        while (fCurElem && !fToEnum->fHash->equals(fLockPrimaryKey, fCurElem->fKey1) )
620            fCurElem = fCurElem->fNext;
621        // if we didn't found it, make so hasMoreElements() returns false
622        if(!fCurElem)
623            fCurHash = fToEnum->fHashModulus;
624        return;
625    }
626    //
627    //  If there is a current element, move to its next element. If this
628    //  hits the end of the bucket, the next block will handle the rest.
629    //
630    if (fCurElem)
631        fCurElem = fCurElem->fNext;
632
633    //
634    //  If the current element is null, then we have to move up to the
635    //  next hash value. If that is the hash modulus, then we cannot
636    //  go further.
637    //
638    if (!fCurElem)
639    {
640        fCurHash++;
641        if (fCurHash == fToEnum->fHashModulus)
642            return;
643
644        // Else find the next non-empty bucket
645        while (fToEnum->fBucketList[fCurHash]==0)
646        {
647            // Bump to the next hash value. If we max out return
648            fCurHash++;
649            if (fCurHash == fToEnum->fHashModulus)
650                return;
651        }
652        fCurElem = fToEnum->fBucketList[fCurHash];
653    }
654}
655
656XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.