source: tags/1.3.5/src/core/RpDict.h @ 5268

Last change on this file since 5268 was 3177, checked in by mmc, 12 years ago

Updated all of the copyright notices to reference the transfer to
the new HUBzero Foundation, LLC.

File size: 32.3 KB
Line 
1/*
2 * ======================================================================
3 *  RpDict
4 *
5 *  AUTHOR:  Derrick Kearney, Purdue University
6 *  Copyright (c) 2004-2012  HUBzero Foundation, LLC
7 *
8 *  See the file "license.terms" for information on usage and
9 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10 * ======================================================================
11 */
12#include <iostream>
13#include <cassert>
14#include <string>
15#include <stdlib.h>
16#include <errno.h>
17
18#ifndef _RpDICT_H
19#define _RpDICT_H
20
21/**************************************************************************/
22/**************************************************************************/
23
24template <  typename KeyType,
25            typename ValType,
26            class _Compare=std::equal_to<KeyType> >
27    class RpDict;
28
29template <  typename KeyType,
30            typename ValType,
31            class _Compare=std::equal_to<KeyType> >
32    class RpDictEntry;
33
34template <  typename KeyType,
35            typename ValType,
36            class _Compare=std::equal_to<KeyType> >
37    class RpDictIterator;
38
39
40/*
41 * RpDictEntry should not depend on _Compare,
42 * it was originally needed because RpDict is a friend class
43 * then i needed to assign it a default value because RpUnits.cc
44 * uses it in its find function. RpUnits::find should really not
45 * have to use it.
46 *
47 * RpDictIterator has the same thing going on. It has a default value
48 * because RpBindingsDict uses it.
49 */
50
51
52/**************************************************************************/
53
54template <typename KeyType, typename ValType, class _Compare>
55class RpDictIterator
56{
57
58    public:
59
60        // retrieve the table the iterator is iterating
61        // virtual RpDict<KeyType,ValType,_Compare>& getTable();
62
63        // send the search iterator to the beginning of the hash table
64        /*virtual*/ RpDictEntry<KeyType,ValType,_Compare>* first();
65
66        // send the search iterator to the next element of the hash table
67        /*virtual*/ RpDictEntry<KeyType,ValType,_Compare>* next();
68/*
69        RpDictIterator(RpDict* table_Ptr)
70            : tablePtr( (RpDict&) *table_Ptr),
71              srchNextEntryPtr(NULL),
72              srchNextIndex(0)
73        {
74        }
75*/
76        RpDictIterator(RpDict<KeyType,ValType,_Compare>& table_Ptr)
77            : tablePtr(table_Ptr),
78              srchNextIndex(0),
79              srchNextEntryPtr(NULL)
80        {
81        }
82
83        // copy constructor
84        RpDictIterator(RpDictIterator<KeyType,ValType,_Compare>& iterRef)
85            : tablePtr(iterRef.tablePtr),
86              srchNextIndex(iterRef.srchNextIndex),
87              srchNextEntryPtr(iterRef.srchNextEntryPtr)
88        {
89        }
90
91        // destructor
92
93    private:
94
95        RpDict<KeyType,ValType,_Compare>&
96            tablePtr;                   /* pointer to the table we want to
97                                         * iterate */
98        int srchNextIndex;              /* Index of next bucket to be
99                                         * enumerated after present one. */
100        RpDictEntry<KeyType,ValType,_Compare>*
101            srchNextEntryPtr;           /* Next entry to be enumerated in the
102                                         * the current bucket. */
103
104};
105
106
107template <typename KeyType, typename ValType, class _Compare>
108class RpDictEntry
109{
110    public:
111
112        operator int() const;
113        // operator==(const RpDictEntry& entry) const;
114        //
115        //operator!=(const RpDictEntry& lhs, const RpDictEntry& rhs) const
116        //{
117        //    if (lhs.key != rhs.key)
118        //}
119        const KeyType* getKey() const;
120        const ValType* getValue() const;
121        // const void* setValue(const void* value);
122        const ValType* setValue(const ValType& value);
123        bool isValid() const;
124
125        // erases this entry from its table
126        void erase();
127
128        friend class RpDict<KeyType,ValType,_Compare>;
129        friend class RpDictIterator<KeyType,ValType,_Compare>;
130
131        // two-arg constructor
132        RpDictEntry(KeyType newKey, ValType newVal)
133           : nextPtr    (NULL),
134             tablePtr   (NULL),
135             hash       (0),
136             clientData (newVal),
137             key        (newKey),
138             valid      (&clientData)
139        {
140        }
141
142        // copy constructor
143        RpDictEntry (const RpDictEntry<KeyType,ValType,_Compare>& entry)
144        {
145            nextPtr     = entry.nextPtr;
146            tablePtr    = entry.tablePtr;
147            hash        = entry.hash;
148
149            if (entry.valid != NULL) {
150                clientData  = (ValType) entry.getValue();
151                key         = (KeyType) entry.getKey();
152                valid       = &clientData;
153            }
154            else {
155                valid = NULL;
156            }
157
158        }
159
160    private:
161
162        RpDictEntry<KeyType,ValType,_Compare>*
163            nextPtr;                /* Pointer to next entry in this
164                                     * hash bucket, or NULL for end of
165                                     * chain. */
166
167        RpDict<KeyType,ValType,_Compare>*
168            tablePtr;              /* Pointer to table containing entry. */
169
170        unsigned int hash;          /* Hash value. */
171
172        ValType clientData;        /* Application stores something here
173                                    * with Tcl_SetHashValue. */
174
175        KeyType key;               /* entry key */
176
177        ValType* valid;            /* is this a valid object */
178
179        RpDictEntry()
180           : nextPtr (NULL),
181             tablePtr (NULL),
182             hash (0),
183             valid (NULL)
184             // clientData (),
185             // key ()
186        {
187        }
188
189};
190
191
192template <typename KeyType, typename ValType, class _Compare>
193class RpDict
194{
195    public:
196
197        typedef bool (*RpDictHint)(ValType);
198
199        // functionality for the user to access/adjust data members
200
201        // checks table size
202        /*virtual*/ int size() const;
203
204        // insert new object into table
205        // returns 0 on success (object inserted or already exists)
206        // returns !0 on failure (object cannot be inserted or dne)
207        //
208        /*virtual*/ RpDict<KeyType,ValType,_Compare>&
209                        set(    KeyType& key,
210                                ValType& value,
211                                RpDictHint hint=NULL,
212                                int *newPtr=NULL,
213                                bool ci=false);
214
215        // find an RpUnits object that should exist in RpUnitsTable
216        //
217        /*virtual*/ RpDictEntry<KeyType,ValType,_Compare>&
218                        find(   KeyType& key,
219                                RpDictHint hint = NULL,
220                                bool ci=false   );
221
222        /*virtual*/ RpDictEntry<KeyType,ValType,_Compare>& operator[]( KeyType& key)
223        {
224            return find(key,NULL);
225        }
226
227        RpDict<KeyType,ValType,_Compare>& setCI( bool val );
228        bool getCI();
229        RpDict<KeyType,ValType,_Compare>& toggleCI();
230
231        // clear the entire table
232        // iterate through the table and call erase on each element
233        /*virtual*/ RpDict<KeyType,ValType,_Compare>& clear();
234
235        // get the nullEntry hash entry for initialization of references
236        /*virtual*/ RpDictEntry<KeyType,ValType,_Compare>& getNullEntry();
237
238        // template <KeyType, ValType> friend class RpDictEntry;
239        // template <KeyType, ValType> friend class RpDictIterator;
240
241        friend class RpDictEntry<KeyType,ValType,_Compare>;
242        friend class RpDictIterator<KeyType,ValType,_Compare>;
243
244        // default constructor
245        RpDict (bool ci=false)
246            : SMALL_RP_DICT_SIZE(4),
247              REBUILD_MULTIPLIER(3),
248              buckets(staticBuckets),
249              numBuckets(SMALL_RP_DICT_SIZE),
250              numEntries(0),
251              rebuildSize(SMALL_RP_DICT_SIZE*REBUILD_MULTIPLIER),
252              downShift(28),
253              mask(3),
254              caseInsensitive(ci)
255        {
256            staticBuckets[0] = staticBuckets[1] = 0;
257            staticBuckets[2] = staticBuckets[3] = 0;
258
259            // setup a dummy entry of NULL
260            nullEntry = new RpDictEntry<KeyType,ValType,_Compare>();
261
262            assert(nullEntry != NULL);
263        }
264
265        // copy constructor
266        // RpDict (const RpDict& dict);
267
268        // assignment operator
269        // RpDict& operator=(const RpDict& dict);
270
271        // destructor
272        /*virtual*/ ~RpDict()
273        {
274            // probably need to delete all the entries as well
275            delete nullEntry;
276        }
277        // make sure to go through the hash table and free all RpDictEntries
278        // because the space is malloc'd in RpDict::set()
279
280
281    private:
282        const int SMALL_RP_DICT_SIZE;
283        const int REBUILD_MULTIPLIER;
284
285        RpDictEntry<KeyType,ValType,_Compare>
286                    **buckets;        /* Pointer to bucket array.  Each
287                                       * element points to first entry in
288                                       * bucket's hash chain, or NULL. */
289        RpDictEntry<KeyType,ValType,_Compare>
290                    *staticBuckets[4];
291                                      /* Bucket array used for small tables
292                                       * (to avoid mallocs and frees). */
293        int numBuckets;               /* Total number of buckets allocated
294                                       * at **bucketPtr. */
295        int numEntries;               /* Total number of entries present
296                                       * in table. */
297        int rebuildSize;              /* Enlarge table when numEntries gets
298                                       * to be this large. */
299        int downShift;                /* Shift count used in hashing
300                                       * function.  Designed to use high-
301                                       * order bits of randomized keys. */
302        int mask;                     /* Mask value used in hashing
303                                       * function. */
304        bool caseInsensitive;         /* When set to true, dictionary uses
305                                       * case insensitive functions,
306                                       * translating chars to uppercase */
307
308        RpDictEntry<KeyType,ValType,_Compare>
309                    *nullEntry;   /* if not const, compiler complains*/
310
311
312
313        // private member fxns
314
315        RpDictEntry<KeyType,ValType,_Compare>*
316            search( KeyType& key, RpDictHint hint = NULL, bool ci = false );
317
318        // static void RpDict::RebuildTable ();
319        void RebuildTable ();
320
321        unsigned int hashFxn(const void* keyPtr) const;
322        unsigned int hashFxn(std::string* keyPtr) const;
323        unsigned int hashFxn(char* keyPtr) const;
324
325        int randomIndex(unsigned int hash);
326};
327
328
329/*--------------------------------------------------------------------------*/
330/*--------------------------------------------------------------------------*/
331
332/**************************************************************************
333 *
334 * int RpDict::size()
335 *  retrieve the size of the structure
336 *
337 * Results:
338 *  Returns size of the hash table
339 *
340 * Side Effects:
341 *  none.
342 *
343 *
344 *************************************************************************/
345
346template <typename KeyType, typename ValType, class _Compare>
347int
348RpDict<KeyType,ValType,_Compare>::size() const
349{
350    return numEntries;
351}
352
353
354/**************************************************************************
355 *
356 * RpDict::set()
357 *  checks to make sure the table exists.
358 *  places a key/value pair into the hash table
359 *
360 * Results:
361 *  Returns a reference to the RpDict object allowing the user to chain
362 *  together different commands such as
363 *      rpdict_obj.set(key).find(a).erase(a);
364 *
365 * Side Effects:
366 *  if successful, the hash table will have a new entry
367 *
368 *
369 *************************************************************************/
370template <typename KeyType, typename ValType, class _Compare>
371RpDict<KeyType,ValType,_Compare>&
372RpDict<KeyType,ValType,_Compare>::set(  KeyType& key,
373                                        ValType& value,
374                                        RpDictHint hint,
375                                        int* newPtr,
376                                        bool ci )
377{
378    RpDictEntry<KeyType,ValType,_Compare> *hPtr = NULL;
379    unsigned int hash = 0;
380    int index = 0;
381    bool oldCI = caseInsensitive;
382
383    assert(&key);
384    assert(&value);
385
386    hPtr = search(key,hint,ci);
387    if (hPtr != NULL) {
388        // adjust the new flag if it was provided
389        if (newPtr) {
390            *newPtr = 0;
391        }
392
393        // adjust the value if it was provided
394        // memory management is left as an exercise for the caller
395        if (&value) {
396            hPtr->setValue(value);
397        }
398
399        // return a reference to the dictionary object
400        return *this;
401    }
402
403    /*
404     * Entry not found.  Add a new one to the bucket.
405     */
406
407    if (&key) {
408        if (ci != oldCI) {
409            setCI(ci);
410        }
411        hash = (unsigned int) hashFxn(&key);
412        if (ci != oldCI) {
413            setCI(oldCI);
414        }
415    }
416    else {
417        // we are creating a NULL key entry.
418        hash = 0;
419    }
420
421    index = randomIndex(hash);
422
423    hPtr = new RpDictEntry<KeyType,ValType,_Compare>(key,value);
424    // hPtr->setValue(value);
425    //
426    // this is just a pointer that was allocated on the heap
427    // it wont stick with the RpDictEntry after the fxn exits...
428    // need to fix still.
429    hPtr->tablePtr = this;
430    hPtr->hash = hash;
431    hPtr->nextPtr = buckets[index];
432    buckets[index] = hPtr;
433    numEntries++;
434
435    if (newPtr) {
436        *newPtr = 1;
437    }
438
439    /*
440     * If the table has exceeded a decent size, rebuild it with many
441     * more buckets.
442     */
443
444    if (numEntries >= rebuildSize) {
445        RebuildTable();
446    }
447
448    // return a reference to the original object
449    return *this;
450}
451
452/*
453 *----------------------------------------------------------------------
454 *
455 *  RpDict::find(KeyType& key, RpDictHint hint)
456 *
457 *  Given a hash table find the entry with a matching key.
458 *
459 * Results:
460 *  The return value is a token for the matching entry in the
461 *  hash table, or NULL if there was no matching entry.
462 *
463 * Side effects:
464 *  None.
465 *
466 *----------------------------------------------------------------------
467 */
468
469template <typename KeyType, typename ValType, class _Compare>
470RpDictEntry<KeyType,ValType,_Compare>&
471RpDict<KeyType,ValType,_Compare>::find( KeyType& key,
472                                        RpDictHint hint,
473                                        bool ci )
474{
475    RpDictEntry<KeyType,ValType,_Compare> *hPtr = NULL;
476
477    hPtr = search(key,hint,ci);
478
479    if (hPtr != NULL) {
480        return *hPtr;
481    }
482
483    // return a reference to the null object
484    // find is not supposed to return a const, but i dont want the user
485    // changing this entry's data members... what to do?
486    return *nullEntry;
487}
488
489/*
490 *----------------------------------------------------------------------
491 *
492 *  RpDict::search(KeyType& key, RpDictHint hint)
493 *
494 *  Given a hash table find the entry with a matching key.
495 *
496 * Results:
497 *  The return value is a token for the matching entry in the
498 *  hash table, or NULL if there was no matching entry.
499 *
500 * Side effects:
501 *  None.
502 *
503 *----------------------------------------------------------------------
504 */
505
506template <typename KeyType, typename ValType, class _Compare>
507RpDictEntry<KeyType,ValType,_Compare>*
508RpDict<KeyType,ValType,_Compare>::search(   KeyType& key,
509                                            RpDictHint hint,
510                                            bool ci )
511                                            // bool ci,
512                                            // RpDictEntryList* entryList)
513{
514    RpDictEntry<KeyType,ValType,_Compare> *hPtr = NULL;
515    unsigned int hash = 0;
516    int index = 0;
517    bool oldCI = caseInsensitive;
518
519    assert(&key);
520
521    // take care of the case where we are creating a NULL key entry.
522    if (&key) {
523        if (ci != oldCI) {
524            // toggle the case insensitivity of the dictionary
525            setCI(ci);
526        }
527
528        hash = (unsigned int) hashFxn(&key);
529
530        if (ci != oldCI) {
531            // reset the case insensitivity of the dictionary
532            setCI(oldCI);
533        }
534    }
535    else {
536        hash = 0;
537    }
538
539    index = randomIndex(hash);
540
541    /*
542     * Search all of the entries in the appropriate bucket.
543     */
544
545    for (hPtr = buckets[index]; hPtr != NULL; hPtr = hPtr->nextPtr) {
546        if (hash != (unsigned int) hPtr->hash) {
547            continue;
548        }
549        if (_Compare()(key, *(hPtr->getKey()))) {
550            // check to see if the user provided a hint
551            if (hint != NULL ) {
552                // if there is a hint, run the potential return value
553                // throught the hint function.
554                if (hint(*(hPtr->getValue())) == true) {
555                    // the hint approves of our choice of return values
556                    // return a reference to the found object
557                    return hPtr;
558                }
559            }
560            else {
561                // return a reference to the found object
562                return hPtr;
563            }
564        }
565    }
566
567    // return a reference to the null object
568    // find is not supposed to return a const, but i dont want the user
569    // changing this entry's data members... what to do?
570    return hPtr;
571
572}
573
574
575
576/**************************************************************************
577 *
578 * virtual RpDict& RpDictIterator::getTable()
579 *  send the search iterator to the beginning of the hash table
580 *
581 * Results:
582 *  returns pointer to the first hash entry of the hash table.
583 *
584 * Side Effects:
585 *  moves iterator to the beginning of the hash table.
586 *
587 *
588 *************************************************************************/
589/*
590template <typename KeyType,typename ValType,class _Compare>
591RpDict<KeyType,ValType,_Compare>&
592RpDictIterator<KeyType,ValType,_Compare>::getTable()
593{
594    return tablePtr;
595}
596*/
597
598/**************************************************************************
599 *
600 * virtual RpDictEntry& RpDict::first()
601 *  send the search iterator to the beginning of the hash table
602 *
603 * Results:
604 *  returns pointer to the first hash entry of the hash table.
605 *
606 * Side Effects:
607 *  moves iterator to the beginning of the hash table.
608 *
609 *
610 *************************************************************************/
611template <typename KeyType,typename ValType,class _Compare>
612RpDictEntry<KeyType,ValType,_Compare>*
613RpDictIterator<KeyType,ValType,_Compare>::first()
614{
615    srchNextIndex = 0;
616    srchNextEntryPtr = NULL;
617    return next();
618}
619
620/**************************************************************************
621 *
622 * Tcl_HashEntry * RpDict::next()
623 *  send the search iterator to the next entry of the hash table
624 *
625 * Results:
626 *  returns pointer to the next hash entry of the hash table.
627 *  if iterator is at the end of the hash table, NULL is returned
628 *  and the iterator is left at the end of the hash table.
629 *
630 * Side Effects:
631 *  moves iterator to the next entry of the hash table if it exists.
632 *
633 *
634 *************************************************************************/
635
636template <typename KeyType,typename ValType,class _Compare>
637RpDictEntry<KeyType,ValType,_Compare>*
638RpDictIterator<KeyType,ValType,_Compare>::next()
639{
640    RpDictEntry<KeyType,ValType,_Compare>* hPtr = NULL;
641
642    while (srchNextEntryPtr == NULL) {
643        if (srchNextIndex >= tablePtr.numBuckets) {
644            return NULL;
645        }
646        srchNextEntryPtr = tablePtr.buckets[srchNextIndex];
647        srchNextIndex++;
648    }
649    hPtr = srchNextEntryPtr;
650    srchNextEntryPtr = hPtr->nextPtr;
651
652    return hPtr;
653}
654
655/**************************************************************************
656 *
657 * RpDict & setCI(bool val)
658 *  Use case insensitive functions where applicable within the dictionary
659 *
660 * Results:
661 *  sets the dictionary objects caseInsensitive variable to the boolean val
662 *
663 * Side Effects:
664 *  mostly find and set functions will begin to execute their functions
665 *  with case insensitivity in mind.
666 *
667 *
668 *************************************************************************/
669template <typename KeyType, typename ValType, class _Compare>
670RpDict<KeyType,ValType,_Compare>&
671RpDict<KeyType,ValType,_Compare>::setCI( bool val )
672{
673    caseInsensitive = val;
674    return *this;
675}
676
677/**************************************************************************
678 *
679 * bool getCI()
680 *  Retrieve the case insensitivity of this dictionary object
681 *
682 * Results:
683 *  returns the dictionary object's caseInsensitive variable to the user
684 *
685 * Side Effects:
686 *  None
687 *
688 *************************************************************************/
689template <typename KeyType, typename ValType, class _Compare>
690bool
691RpDict<KeyType,ValType,_Compare>::getCI()
692{
693    return caseInsensitive;
694}
695
696/**************************************************************************
697 *
698 * RpDict & toggleCI()
699 *  Toggle the case insensitivity of this dictionary object
700 *
701 * Results:
702 *  returns the dictionary object's caseInsensitive variable to the user
703 *
704 * Side Effects:
705 *  None
706 *
707 *************************************************************************/
708template <typename KeyType, typename ValType, class _Compare>
709RpDict<KeyType,ValType,_Compare>&
710RpDict<KeyType,ValType,_Compare>::toggleCI()
711{
712    caseInsensitive = !caseInsensitive;
713    return *this;
714}
715
716/**************************************************************************
717 *
718 * RpDict & clear()
719 *  iterate through the table and call erase on each element
720 *
721 * Results:
722 *  empty hash table
723 *
724 * Side Effects:
725 *  every element of the hash table will be erased.
726 *
727 *
728 *************************************************************************/
729template <typename KeyType, typename ValType, class _Compare>
730RpDict<KeyType,ValType,_Compare>&
731RpDict<KeyType,ValType,_Compare>::clear()
732{
733    RpDictEntry<KeyType,ValType,_Compare> *hPtr = NULL;
734    RpDictIterator<KeyType,ValType,_Compare> iter((RpDict&)*this);
735
736    hPtr = iter.first();
737
738    while (hPtr) {
739        hPtr->erase();
740        hPtr = iter.next();
741    }
742
743    return *this;
744}
745
746/**************************************************************************
747 *
748 * RpDictEntry & getNullEntry()
749 *  get the nullEntry hash entry for initialization of references
750 *
751 *
752 * Results:
753 *  nullEntry RpDictEntry related to this dictionary is returned
754 *
755 * Side Effects:
756 *  none
757 *
758 *
759 *************************************************************************/
760template <typename KeyType, typename ValType, class _Compare>
761RpDictEntry<KeyType,ValType,_Compare>&
762RpDict<KeyType,ValType,_Compare>::getNullEntry()
763{
764    return *nullEntry;
765}
766
767
768/*
769 *----------------------------------------------------------------------
770 *
771 * void RpDictEntry::erase()
772 *
773 *  Remove a single entry from a hash table.
774 *
775 * Results:
776 *  None.
777 *
778 * Side effects:
779 *  The entry given by entryPtr is deleted from its table and
780 *  should never again be used by the caller.  It is up to the
781 *  caller to free the clientData field of the entry, if that
782 *  is relevant.
783 *
784 *----------------------------------------------------------------------
785 */
786
787template <typename KeyType, typename ValType, class _Compare>
788void
789RpDictEntry<KeyType,ValType,_Compare>::erase()
790{
791    RpDictEntry<KeyType,ValType,_Compare> *prevPtr = NULL;
792    RpDictEntry<KeyType,ValType,_Compare> **bucketPtr = NULL;
793    int index = 0;
794
795    // check to see if the object is associated with a table
796    // if object is not associated with a table, there is no
797    // need to try to remove it from the table.
798    if (tablePtr) {
799
800        index = tablePtr->randomIndex(hash);
801
802        // calculate which bucket the entry should be in.
803        bucketPtr = &(tablePtr->buckets[index]);
804
805        // remove the entry from the buckets
806        //
807        // if entry is the first entry in the bucket
808        // move the bucket to point to the next entry
809        if ((*bucketPtr)->key == this->key) {
810            *bucketPtr = nextPtr;
811        }
812        else {
813            // if the entry is not the first entry in the bucket
814            // search for the entry
815            for (prevPtr = *bucketPtr; ; prevPtr = prevPtr->nextPtr) {
816
817                // printf("malformed bucket chain in RpDictEntry::erase()");
818                assert(prevPtr != NULL);
819
820                if (prevPtr->nextPtr == this) {
821                    prevPtr->nextPtr = nextPtr;
822                    break;
823                }
824            } // end for loop
825        } // end else
826
827        // update our table's information
828        tablePtr->numEntries--;
829
830    } // end if tablePtr
831
832    // invalidate the object
833    nextPtr = NULL;
834    tablePtr = NULL;
835    hash = 0;
836    // clientData = NULL;
837    // key = NULL;
838    valid = NULL;
839
840    // delete the object.
841    delete this;
842
843}
844
845
846/*
847 *----------------------------------------------------------------------
848 *
849 * const char* RpDictEntry::getKey() const
850 *
851 *  retrieve the key of the current object
852 *
853 * Results:
854 *  the key is returned to the caller
855 *
856 * Side effects:
857 *  None.
858 *
859 *----------------------------------------------------------------------
860 */
861
862template <typename KeyType, typename ValType, class _Compare>
863const KeyType*
864RpDictEntry<KeyType,ValType,_Compare>::getKey() const
865{
866    return (const KeyType*) &key;
867}
868
869/*
870 *----------------------------------------------------------------------
871 *
872 * const char* RpDictEntry::getValue() const
873 *
874 *  retrieve the value of the current object
875 *  it is the caller responsibility to check isValid() to see if the
876 *  object actually holds a valid value.
877 *
878 * Results:
879 *  the value is returned to the caller
880 *
881 * Side effects:
882 *  None.
883 *
884 *----------------------------------------------------------------------
885 */
886
887template <typename KeyType, typename ValType, class _Compare>
888const ValType*
889RpDictEntry<KeyType,ValType,_Compare>::getValue() const
890{
891    return (const ValType*) &clientData;
892}
893
894/*
895 *----------------------------------------------------------------------
896 *
897 * const void* RpDictEntry::setValue()
898 *
899 *  retrieve the value of the current object
900 *
901 * Results:
902 *  the value is returned to the caller
903 *
904 * Side effects:
905 *  None.
906 *
907 *----------------------------------------------------------------------
908 */
909
910template <typename KeyType, typename ValType, class _Compare>
911const ValType*
912RpDictEntry<KeyType,ValType,_Compare>::setValue(const ValType& value)
913{
914    clientData = value;
915    valid = &clientData;
916    return (const ValType*) &clientData;
917}
918
919template <typename KeyType, typename ValType, class _Compare>
920RpDictEntry<KeyType,ValType,_Compare>::operator int() const
921{
922
923    if (!tablePtr && hash == 0)
924        return 0;
925    else
926        return 1;
927
928//    return (key);
929}
930
931/*
932 *----------------------------------------------------------------------
933 *
934 * bool RpDictEntry::isValid()
935 *
936 *  is this a valid object, return true or false
937 *
938 * Results:
939 *  tells the user if the object is valid true or false
940 *
941 * Side effects:
942 *  None.
943 *
944 *----------------------------------------------------------------------
945 */
946
947template <typename KeyType, typename ValType, class _Compare>
948bool
949RpDictEntry<KeyType,ValType,_Compare>::isValid() const
950{
951    if (valid) {
952        return true;
953    }
954    return false;
955}
956
957
958/*************************************************************************/
959/*************************************************************************/
960
961/*
962 *----------------------------------------------------------------------
963 *
964 * RebuildTable --
965 *
966 *  This procedure is invoked when the ratio of entries to hash
967 *  buckets becomes too large.  It creates a new table with a
968 *  larger bucket array and moves all of the entries into the
969 *  new table.
970 *
971 * Results:
972 *  None.
973 *
974 * Side effects:
975 *  Memory gets reallocated and entries get re-hashed to new
976 *  buckets.
977 *
978 *----------------------------------------------------------------------
979 */
980
981template <typename KeyType, typename ValType, class _Compare>
982void
983RpDict<KeyType,ValType,_Compare>::RebuildTable()
984{
985    int oldSize=0, count=0, index=0;
986    RpDictEntry<KeyType,ValType,_Compare> **oldBuckets = NULL;
987    RpDictEntry<KeyType,ValType,_Compare> **oldChainPtr = NULL, **newChainPtr = NULL;
988    RpDictEntry<KeyType,ValType,_Compare> *hPtr = NULL;
989
990    oldSize = numBuckets;
991    oldBuckets = buckets;
992
993    /*
994     * Allocate and initialize the new bucket array, and set up
995     * hashing constants for new array size.
996     */
997
998
999    numBuckets *= 4;
1000
1001    buckets = (RpDictEntry<KeyType,ValType,_Compare> **) malloc((unsigned)
1002        (numBuckets * sizeof(RpDictEntry<KeyType,ValType,_Compare> *)));
1003
1004    for (count = numBuckets, newChainPtr = buckets;
1005        count > 0;
1006        count--, newChainPtr++) {
1007
1008        *newChainPtr = NULL;
1009    }
1010
1011    rebuildSize *= 4;
1012    downShift -= 2;
1013    mask = (mask << 2) + 3;
1014
1015    /*
1016     * Rehash all of the existing entries into the new bucket array.
1017     */
1018
1019    for (oldChainPtr = oldBuckets; oldSize > 0; oldSize--, oldChainPtr++) {
1020        for (hPtr = *oldChainPtr; hPtr != NULL; hPtr = *oldChainPtr) {
1021            *oldChainPtr = hPtr->nextPtr;
1022
1023            index = randomIndex(hPtr->hash);
1024
1025            hPtr->nextPtr = buckets[index];
1026            buckets[index] = hPtr;
1027        }
1028    }
1029
1030    /*
1031     * Free up the old bucket array, if it was dynamically allocated.
1032     */
1033
1034    if (oldBuckets != staticBuckets) {
1035        free((char *) oldBuckets);
1036    }
1037}
1038
1039/*
1040 *----------------------------------------------------------------------
1041 *
1042 * hashFxn --
1043 *
1044 *  Compute a one-word summary of a text string, which can be
1045 *  used to generate a hash index.
1046 *
1047 * Results:
1048 *  The return value is a one-word summary of the information in
1049 *  string.
1050 *
1051 * Side effects:
1052 *  None.
1053 *
1054 *----------------------------------------------------------------------
1055 */
1056
1057template <typename KeyType, typename ValType, class _Compare>
1058unsigned int
1059RpDict<KeyType,ValType,_Compare>::hashFxn(const void *keyPtr) const
1060{
1061    const char *stopAddr = (const char *) keyPtr + sizeof(&keyPtr) - 1 ;
1062    const char *str = (const char *) keyPtr;
1063    unsigned int result = 0;
1064    int c;
1065
1066    result = 0;
1067
1068    while (str != stopAddr) {
1069        c = *str;
1070        result += (result<<3) + c;
1071        str++;
1072    }
1073
1074    return result;
1075}
1076
1077/*
1078 * Quote from Tcl's hash table code
1079 * I tried a zillion different hash functions and asked many other
1080 * people for advice.  Many people had their own favorite functions,
1081 * all different, but no-one had much idea why they were good ones.
1082 * I chose the one below (multiply by 9 and add new character)
1083 * because of the following reasons:
1084 *
1085 * 1. Multiplying by 10 is perfect for keys that are decimal strings,
1086 *    and multiplying by 9 is just about as good.
1087 * 2. Times-9 is (shift-left-3) plus (old).  This means that each
1088 *    character's bits hang around in the low-order bits of the
1089 *    hash value for ever, plus they spread fairly rapidly up to
1090 *    the high-order bits to fill out the hash value.  This seems
1091 *    works well both for decimal and non-decimal strings.
1092 */
1093
1094
1095template <typename KeyType, typename ValType, class _Compare>
1096unsigned int
1097RpDict<KeyType,ValType,_Compare>::hashFxn(std::string* keyPtr) const
1098{
1099    const char *str = (const char *) (keyPtr->c_str());
1100    unsigned int result = 0;
1101    int c = 0;
1102
1103    result = 0;
1104
1105    while (1) {
1106        // c = *str;
1107
1108        if (caseInsensitive == true) {
1109            c = toupper(static_cast<unsigned char>(*str));
1110        }
1111        else {
1112            c = *str;
1113        }
1114
1115        if (c == 0) {
1116            break;
1117        }
1118        result += (result<<3) + c;
1119        str++;
1120    }
1121
1122    return result;
1123}
1124
1125template <typename KeyType, typename ValType, class _Compare>
1126unsigned int
1127RpDict<KeyType,ValType,_Compare>::hashFxn(char* keyPtr) const
1128{
1129    const char *str = (const char *) (keyPtr);
1130    unsigned int result = 0;
1131    int c = 0;
1132
1133    result = 0;
1134
1135    while (1) {
1136        c = *str;
1137        if (c == 0) {
1138            break;
1139        }
1140        result += (result<<3) + c;
1141        str++;
1142    }
1143
1144    return result;
1145}
1146
1147/*
1148 * ---------------------------------------------------------------------
1149 *
1150 * int RpDict::randomIndex(hash)
1151 *
1152 * The following macro takes a preliminary integer hash value and
1153 * produces an index into a hash tables bucket list.  The idea is
1154 * to make it so that preliminary values that are arbitrarily similar
1155 * will end up in different buckets.  The hash function was taken
1156 * from a random-number generator.
1157 *
1158 * ---------------------------------------------------------------------
1159 */
1160
1161template <typename KeyType, typename ValType, class _Compare>
1162int
1163RpDict<KeyType,ValType,_Compare>::randomIndex(unsigned int hash)
1164{
1165    return (((((long) (hash))*1103515245) >> downShift) & mask);
1166}
1167
1168
1169
1170#endif
Note: See TracBrowser for help on using the repository browser.