source: branches/1.7/src/core/RpDict.h @ 6694

Last change on this file since 6694 was 5850, checked in by gah, 9 years ago

merge accumulative changes from 1.3 branch into uq branch

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