source: branches/1.3/src/core/RpDict.h @ 5675

Last change on this file since 5675 was 5675, checked in by ldelgass, 9 years ago

merge r5673 from trunk (eol-style)

  • Property svn:eol-style set to native
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.